Call the default asp.net HttpHandler from a custom handler

我的梦境 提交于 2019-12-03 07:28:27

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!