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

发布于 2024-09-06 06:57:08 字数 1014 浏览 4 评论 0原文

我试图在 IRouteHandler 类的 GettHttpHandler 方法中启用会话,但会话始终为空。有人可以告诉我我做错了什么吗?

在 global.asax 中,我有

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

MyRouteHandler 类,其中 Session 为 null 如下所示:

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...)层次结构组成,可以正常发布或预览。浏览网站的内容制作者可以选择仅查看普通页面或发布预览的页面。浏览模式存储在用户的会话中,因此路由处理程序需要知道浏览模式才能解决所请求的页面。

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

I'm trying to get Session enabled in the GettHttpHandler method of my IRouteHandler classes but session is always null. Could someone tell me what I'm doing wrong?

In global.asax I have

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

The MyRouteHandler class where Session is null looks like this:

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

I made a small test app that shows the problem.

Could someone tell me what I'm doing wrong?

Edited to add:

Yes, I really need session data in the route handler. There are many reasons but one easily explainable is when the user can switch to browse the site in preview mode.

The site consists of a hierarchy of dynamic pages (/page1/page2...) in the database that can be published normally or to preview. A content producer browsing the site can choose to view just normal pages or also those published to preview. The browsing mode is stored in the user's session so therefor the route handler needs to know the browsing mode to be able to solve the requested page.

So I really need the session already at that stage.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

没︽人懂的悲伤 2024-09-13 06:57:08

我在这个答案中解释了这个问题背后的原因。现在我已经找到了解决问题的方法!

  1. 您创建一个自定义HttpHandler类:

    类 MyHttpHandler :IHttpHandler、IRequiresSessionState
    {
      公共 MyRequestHandler 请求处理程序;
      公共RequestContext上下文;
      公共MyHttpHandler(MyRequestHandler路由处理程序,RequestContext上下文)
      {
        请求处理程序=路由处理程序;
        上下文=上下文;
      }
    
      公共无效ProcessRequest(HttpContext上下文)
      {
        抛出新的NotImplementedException();
      }
    
      public bool 是否可重用
      {
        获取 { 抛出新的 NotImplementedException(); }
      }
    }
    

添加IRequiresSessionState接口非常重要,否则IIS不会为此请求加载会话。我们不需要实现ProcessRequestIsReusable的逻辑,但是类必须实现IHttpHandler接口。

  1. 您更改 RouteHandler 实现:

    公共类 MyRequestHandler : IRouteHandler
    {
      公共 IHttpHandler GetHttpHandler(RequestContext requestContext)
      {
          返回新的 MyHttpHandler(this, requestContext);
      }
    
      公共 IHttpHandler DelayedGetHttpHandler(RequestContext requestContext)
      {
          // 你的自定义路由逻辑在这里...
      }
    }
    

您只需将原始的、与会话相关的逻辑移至 DelayedGetHttpHandler 函数,并在 GetHttphandler 函数中返回一个实例帮助 MyHttpHandler 类。

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

    全局公共类:HttpApplication
    {
        公共重写 void Init()
        {
            基.Init();
            PostAcquireRequestState += Global_PostAcquireRequestState;
        }
     }
    

有关更多参考,请查看此页面:https://msdn.microsoft.com/en-us/library/bb470252 (v=vs.140).aspx。它解释了请求生命周期以及我使用 PostAcquireRequestState 事件的原因。

  1. 在事件处理程序中,您调用自定义 RouteHandling 函数:

    void Global_PostAcquireRequestState(对象发送者,EventArgs e)
    {
       if (HttpContext.Current.Handler 是 MyHttpHandler) {
         var handler = HttpContext.Current.Handler as MyHttpHandler;
         HttpContext.Current.Handler = handler.RouteHandler.DelayedGetHttpHandler(handler.Context);
       }
    }
    

就是这样。对我有用。

I have explained reason behind this problem in this answer. And now I have found a solution to the problem!

  1. You create a custom HttpHandler class:

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

It is important to add IRequiresSessionState interface, otherwise IIS does not load session for this request. We do not need to implement logic of ProcessRequest and IsReusable, but class must implement the IHttpHandler interface.

  1. You change your RouteHandler implementation:

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

You simply move your original, Session dependent logic to DelayedGetHttpHandler function and in the GetHttphandler function you return an instance of the helping MyHttpHandler class.

  1. Then, you hook your handling logic to the HttpApplication.PostAcquireRequestState event, e.g. in the Global.asax:

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

For more reference, check this page: https://msdn.microsoft.com/en-us/library/bb470252(v=vs.140).aspx. It explains the request lifecycle and why I use the PostAcquireRequestState event.

  1. In the event handler, you invoke your custom RouteHandling function:

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

And that's it. Works for me.

放肆 2024-09-13 06:57:08

我不确定你能做到这一点(尽管我可能是错的)。我记得 IRequiresSessionState 指示 HttpHandler 需要会话状态,而不是路由处理程序(路由处理程序负责为您提供适合该路由的处理程序)。

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

I am not sure that you can do this (although I may be wrong). My recollection is that IRequiresSessionState indicates that an HttpHandler needs session state, rather than the route handler (which is responsible for giving you a handler appropriate to the route).

Do you really need the session in the route handler itself and not the handler it gives out?

清秋悲枫 2024-09-13 06:57:08

好吧,我知道这是旧线程,但如果像我这样的人遇到同样的情况,我只是将答案放在这里,我找到了答案 此处

您所做的只是将 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 的模块部分,这是比前一个更好的解决方案。

Well I know this is old thread but just putting up the answer here if anyone like me falls in the same scenario, I found an answer here

What you do is just add a runAllManagedModulesForAllRequests="true" attribute to your modules tag in web.config like below

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

However this is not a good solution as it calls managed module everytime, i am using

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

add it in modules section of web.config, this a better solution than the previous one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文