Вызовите HttpHandler asp.net по умолчанию из настраиваемого обработчика

Я добавляю маршрутизацию ASP.NET в старое приложение веб-форм. Я использую кастомный HttpHandler для обработки всего. В некоторых ситуациях я хотел бы сопоставить конкретный путь с файлом aspx, поэтому мне нужно просто передать управление обратно HttpHandler по умолчанию для asp.net.

Самое близкое, что я получил, это

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
}

Он ничего не делает, в поток ничего не выводится. В документации MS для System.Web.UI.Page (как IHttpHandler) говорится что-то вроде «не вызывайте метод ProcessRequest. Он предназначен для внутреннего использования».

Глядя вокруг, кажется, что вы можете сделать это с помощью MVC, например. : MvcHttpHandler, похоже, не реализует IHttpHandler

Также есть эта штука System.Web.UI.PageHandlerFactory, которая, похоже, просто создаст обработчик страницы для файла aspx, но он внутренний, и я не могу использовать его напрямую.

Эта страница: http://msdn.microsoft.com/en-us/library/bb398986.aspx относится к «обработчику asp.net по умолчанию», но не идентифицирует класс и не дает никаких указаний на то, как его можно использовать.

Есть идеи, как я могу это сделать? Является ли это возможным?


person Jamie Treworgy    schedule 29.03.2012    source источник


Ответы (3)


Настойчивость окупается! Это действительно работает, и, поскольку эта информация, похоже, почти нигде недоступна, я подумал, что отвечу на свой вопрос. Спасибо Роберту за этот пост о создании экземпляров вещей с помощью внутренних конструкторов, это ключ.

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);
}

... и, как какое-то маленькое чудо, страница aspx обрабатывается и отображается полностью в процессе без необходимости перенаправления.

Я ожидаю, что это будет работать только в IIS7.

person Jamie Treworgy    schedule 29.03.2012

Я использую маршрутизацию в веб-формах, у вас должна быть возможность просто добавить маршрут игнорирования для конкретных файлов .aspx, которые вам нужны. Затем это будет обработано HttpHandler по умолчанию.

http://msdn.microsoft.com/en-us/library/dd505203.aspx

person Dave Loukola    schedule 29.03.2012
comment
Я пытаюсь сопоставить другой маршрут с файлом, например Я хочу, чтобы / a / b / c вызывал default.aspx? Path = a / b / c без перенаправления. Я уже игнорирую * .aspx. - person Jamie Treworgy; 29.03.2012
comment
+1 за то, чтобы не усложнять. Редиректы - не проблема. Кроме того, ваш ответ отлично подходит для более общих поисковых запросов Google, по которым вы попадаете на эту страницу. - person Thabo; 04.06.2014

Другой вариант - инвертировать логику, обработав случаи, в которых вы НЕ хотите возвращать ответ по умолчанию, и переназначить остальные на свой собственный IHttpHandler. Всякий раз, когда myCondition ложно, ответ будет «по умолчанию». Переключатель реализован как 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; }
}
person Marc    schedule 03.11.2016