Сессия пуста в IRouteHandler.GetHttpHandler с маршрутизацией Asp.net - PullRequest
5 голосов
/ 18 июня 2010

Я пытаюсь включить сеанс в методе GettHttpHandler моих классов IRouteHandler, но сеанс всегда равен нулю.Может кто-нибудь сказать мне, что я делаю не так?

В global.asax у меня есть

RouteTable.Routes.Add("All", new Route("{*page}", new MyRouteHandler()));

Класс MyRouteHandler, где Session равен нулю, выглядит так:

public class MyRouteHandler : IRouteHandler, IRequiresSessionState
{
    public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        string test = HttpContext.Current.Session["test"].ToString();
        return BuildManager.CreateInstanceFromVirtualPath("~/Page.aspx", typeof(Page)) as Page;
    }
}

Я сделал небольшое тестовое приложение , которое показывает проблему.

Может кто-нибудь сказать мне, что я делаю неправильно?

Отредактировано длядобавить:

Да, мне действительно нужны данные сеанса в обработчике маршрута.Есть много причин, но одна легко объяснима, когда пользователь может переключиться на просмотр сайта в режиме предварительного просмотра.

Сайт состоит из иерархии динамических страниц (/ page1 / page2 ...) в базе данных, котораямогут быть опубликованы в обычном режиме или для предварительного просмотра.Производитель контента, просматривающий сайт, может выбрать просмотр только обычных страниц или страниц, опубликованных для предварительного просмотра.Режим просмотра сохраняется в сеансе пользователя, поэтому обработчик маршрута должен знать режим просмотра, чтобы иметь возможность решить запрошенную страницу.

Так что мне действительно нужен сеанс уже на этом этапе.

Ответы [ 3 ]

8 голосов
/ 08 февраля 2015

Я объяснил причину этой проблемы в этом ответе . И вот теперь я нашел решение проблемы!

  1. Вы создаете пользовательский HttpHandler класс:

    class MyHttpHandler : IHttpHandler, IRequiresSessionState
    {
      public MyRequestHandler RequestHandler;
      public RequestContext Context;
      public MyHttpHandler(MyRequestHandler routeHandler, RequestContext context)
      {
        RequestHandler = routeHandler;
        Context = context;
      }
    
      public void ProcessRequest(HttpContext context)
      {
        throw new NotImplementedException();
      }
    
      public bool IsReusable
      {
        get { throw new NotImplementedException(); }
      }
    }
    

Важно добавить интерфейс IRequiresSessionState , в противном случае IIS не загружает сеанс для этого запроса. Нам не нужно реализовывать логику ProcessRequest и IsReusable, но класс должен реализовывать интерфейс IHttpHandler.

  1. Вы меняете реализацию RouteHandler:

    public class MyRequestHandler : IRouteHandler
    {
      public IHttpHandler GetHttpHandler(RequestContext requestContext)
      {
          return new MyHttpHandler(this, requestContext);
      }
    
      public IHttpHandler DelayedGetHttpHandler(RequestContext requestContext)
      {
          // your custom routing logic comes here...
      }
    }
    

Вы просто перемещаете исходную логику, зависящую от сеанса, в функцию DelayedGetHttpHandler, а в функции GetHttphandler вы возвращаете экземпляр вспомогательного класса MyHttpHandler.

  1. Затем вы подключаете свою логику обработки к событию HttpApplication.PostAcquireRequestState, например, в Global.asax:

    public class Global : HttpApplication
    {
        public override void Init()
        {
            base.Init();
            PostAcquireRequestState += Global_PostAcquireRequestState;
        }
     }
    

Для получения дополнительной информации посетите эту страницу: https://msdn.microsoft.com/en-us/library/bb470252(v=vs.140).aspx. В ней объясняется жизненный цикл запроса и почему я использую событие PostAcquireRequestState.

  1. В обработчике событий вы вызываете пользовательскую функцию RouteHandling:

    void Global_PostAcquireRequestState(object sender, EventArgs e)
    {
       if (HttpContext.Current.Handler is MyHttpHandler) {
         var handler = HttpContext.Current.Handler as MyHttpHandler;
         HttpContext.Current.Handler = handler.RouteHandler.DelayedGetHttpHandler(handler.Context);
       }
    }
    

И это все. У меня работает.

1 голос
/ 29 декабря 2011

Ну, я знаю, что это старая ветка, но просто выкладываю ответ здесь, если кто-то, как я, попадает в тот же сценарий, я нашел ответ здесь

Что вы делаете, просто добавляете атрибут runAllManagedModulesForAllRequests = "true" в тег модуля в файле web.config, как показано ниже

    <system.webServer>
    .....
       <modules runAllManagedModulesForAllRequests="true">
       ........
       </modules>
    ......
    </system.webServer>

Однако это не очень хорошее решение, так как оно вызывает управляемый модуль каждый раз, я использую

    <remove name="Session" />
    <add name="Session" type="System.Web.SessionState.SessionStateModule"/>

добавьте его в раздел модулей web.config, это лучшее решение, чем предыдущее.

1 голос
/ 18 июня 2010

Я не уверен, что вы можете сделать это (хотя я могу ошибаться). Насколько я помню, IRequiresSessionState указывает, что HttpHandler нужно состояние сеанса, а не обработчик маршрута (который отвечает за предоставление обработчика, соответствующего маршруту).

Вам действительно нужен сеанс в самом обработчике маршрута, а не в обработчике, который он выдает?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...