问题
I'm adding ASP.NET routing to an older webforms app. I'm using a custom HttpHandler
to process everything. In some situations I would like to map a particular path back to an aspx
file, so I need to just pass control back to the default HttpHandler for asp.net.
The closest I've gotten is this
public void ProcessRequest(HttpContext context) {
// .. when we decide to pass it on
var handler = new System.Web.UI.Page();
handler.ProcessRequest(context);
MemoryStream steam = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
HtmlTextWriter htmlWriter = new HtmlTextWriter(writer);
handler.RenderControl(htmlWriter);
// write headers, etc. & send stream to Response
}
It doesn't do anything, there's nothing output to the stream. MS's documentation for System.Web.UI.Page (as an IHttpHandler) say something to the effect of "do not call the ProcessRequest method. It's for internal use."
From looking around it seems like you can do this with MVC, e.g. : MvcHttpHandler doesn't seem to implement IHttpHandler
There is also this thing System.Web.UI.PageHandlerFactory
which appears that it would just produce a Page handler for an aspx file, but it's internal and I can't use it directly.
This page: http://msdn.microsoft.com/en-us/library/bb398986.aspx refers to the "default asp.net handler" but does not identify a class or give any indication how one might use it.
Any ideas on how I can do this? Is it possible?
回答1:
Persistence pays off! This actually works, and since this information seems to be available pretty much nowhere I thought I'd answer my own question. Thanks to Robert for this post on instantiating things with internal constructors, this is the key.
http://www.rvenables.com/2009/08/instantiating-classes-with-internal-constructors/
public void ProcessRequest(HttpContext context) {
// the internal constructor doesn't do anything but prevent you from instantiating
// the factory, so we can skip it.
PageHandlerFactory factory =
(PageHandlerFactory)System.Runtime.Serialization.FormatterServices
.GetUninitializedObject(typeof(System.Web.UI.PageHandlerFactory));
string newTarget = "default.aspx";
string newQueryString = // whatever you want
string oldQueryString = context.Request.QueryString.ToString();
string queryString = newQueryString + oldQueryString!="" ?
"&" + newQueryString :
"";
// the 3rd parameter must be just the file name.
// the 4th parameter should be the physical path to the file, though it also
// works fine if you pass an empty string - perhaps that's only to override
// the usual presentation based on the path?
var handler = factory.GetHandler(context, "GET",newTarget,
context.Request.MapPath(context,newTarget));
// Update the context object as it should appear to your page/app, and
// assign your new handler.
context.RewritePath(newTarget , "", queryString);
context.Handler = handler;
// .. and done
handler.ProcessRequest(context);
}
... and like some small miracle, an aspx page processes & renders completely in-process without the need to redirect.
I expect this will only work in IIS7.
回答2:
I'm you're using Routing in webforms you should be able to just add an ignore route for the specific .aspx files you want. This will then be handled by the default HttpHandler.
http://msdn.microsoft.com/en-us/library/dd505203.aspx
回答3:
Another option is to invert the logic by handling the cases in which you do NOT want to return the default response and remap the others to your own IHttpHandler. Whenever myCondition is false, the response will be the "default". The switch is implemented as an IHttpModule:
public class SwitchModule: IHttpModule
{
public void Init(HttpApplication context)
{
context.PostAuthenticateRequest += app_PostAuthenticateRequest;
}
void app_PostAuthenticateRequest(object sender, EventArgs e)
{
// Check for whatever condition you like
if (true)
HttpContext.Current.RemapHandler(new CustomHandler());
}
public void Dispose()
}
internal class CustomHandler: IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.Write("hallo");
}
public bool IsReusable { get; }
}
来源:https://stackoverflow.com/questions/9930880/call-the-default-asp-net-httphandler-from-a-custom-handler