使用Asp.net路由的IRouteHandler.GetHttpHandler中的会话为空

时间:2010-06-18 07:42:26

标签: asp.net session routing null iroutehandler

我正在尝试在我的IRouteHandler类的GettHttpHandler方法中启用Session,但session始终为null。有人能告诉我我做错了吗?

在global.asax我有

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

Session为null的MyRouteHandler类如下所示:

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

我做了一个显示问题的小test app

有人能告诉我我做错了吗?

编辑添加:

是的,我真的需要路由处理程序中的会话数据。有很多原因,但可以轻松解释的是当用户可以切换到以预览模式浏览网站时。

该网站由数据库中的动态页面层次结构(/ page1 / page2 ...)组成,可以正常发布或预览。浏览网站的内容制作者可以选择仅查看普通页面或查看发布到预览的页面。浏览模式存储在用户的会话中,因此路由处理程序需要知道浏览模式才能解析所请求的页面。

所以我真的需要在那个阶段进行会议。

3 个答案:

答案 0 :(得分:8)

我已在this answer中解释了此问题背后的原因。现在我找到了解决问题的方法!

  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(); }
      }
    }
    
  2. 添加 IRequiresSessionState 接口非常重要,否则IIS不会为此请求加载会话。我们不需要实现ProcessRequestIsReusable的逻辑,但类必须实现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...
        }
      }
      
    2. 您只需将原始的会话相关逻辑移动到DelayedGetHttpHandler函数,并在GetHttphandler函数中返回帮助MyHttpHandler类的实例。

      1. 然后,您将处理逻辑挂钩到HttpApplication.PostAcquireRequestState事件,例如在Global.asax中:

        public class Global : HttpApplication
        {
            public override void Init()
            {
                base.Init();
                PostAcquireRequestState += Global_PostAcquireRequestState;
            }
         }
        
      2. 有关详细信息,请查看此页面: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);
             }
          }
          
        2. 就是这样。适合我。

答案 1 :(得分:1)

我不确定你能做到这一点(虽然我可能错了)。我的回忆是,IRequiresSessionState表示HttpHandler需要会话状态,而不是路由处理程序(它负责为您提供适合该路由的处理程序)。

你真的需要路由处理程序本身的会话,而不是它给出的处理程序吗?

答案 2 :(得分:1)

嗯,我知道这是旧帖子,但如果有人像我这样的人在同一场景中,我就找到答案here

你所做的只是在web.config中的modules标签中添加一个runAllManagedModulesForAllRequests =“true”属性,如下所示

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

然而,这不是一个好的解决方案,因为它每次调用托管模块,我正在使用

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

将它添加到web.config的modules部分,这是一个比前一个更好的解决方案。