我可以从HTTPModule访问会话状态吗?


85

我真的可以从我的HTTPModule中更新用户的会话变量,但是据我所知,这是不可能的。

更新:我的代码当前正在OnBeginRequest ()事件处理程序中运行。

更新:到目前为止收到的建议,我尝试将其添加到Init ()我的HTTPModule例程中:

AddHandler context.PreRequestHandlerExecute, AddressOf OnPreRequestHandlerExecute

但是在我的OnPreRequestHandlerExecute例行程序中,会话状态仍然不可用!

谢谢,如果我错过了一些东西,我们深表歉意!

Answers:


83

ASP.NET论坛上找到了这一点:

using System;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Diagnostics;

// This code demonstrates how to make session state available in HttpModule,
// regardless of requested resource.
// author: Tomasz Jastrzebski

public class MyHttpModule : IHttpModule
{
   public void Init(HttpApplication application)
   {
      application.PostAcquireRequestState += new EventHandler(Application_PostAcquireRequestState);
      application.PostMapRequestHandler += new EventHandler(Application_PostMapRequestHandler);
   }

   void Application_PostMapRequestHandler(object source, EventArgs e)
   {
      HttpApplication app = (HttpApplication)source;

      if (app.Context.Handler is IReadOnlySessionState || app.Context.Handler is IRequiresSessionState) {
         // no need to replace the current handler
         return;
      }

      // swap the current handler
      app.Context.Handler = new MyHttpHandler(app.Context.Handler);
   }

   void Application_PostAcquireRequestState(object source, EventArgs e)
   {
      HttpApplication app = (HttpApplication)source;

      MyHttpHandler resourceHttpHandler = HttpContext.Current.Handler as MyHttpHandler;

      if (resourceHttpHandler != null) {
         // set the original handler back
         HttpContext.Current.Handler = resourceHttpHandler.OriginalHandler;
      }

      // -> at this point session state should be available

      Debug.Assert(app.Session != null, "it did not work :(");
   }

   public void Dispose()
   {

   }

   // a temp handler used to force the SessionStateModule to load session state
   public class MyHttpHandler : IHttpHandler, IRequiresSessionState
   {
      internal readonly IHttpHandler OriginalHandler;

      public MyHttpHandler(IHttpHandler originalHandler)
      {
         OriginalHandler = originalHandler;
      }

      public void ProcessRequest(HttpContext context)
      {
         // do not worry, ProcessRequest() will not be called, but let's be safe
         throw new InvalidOperationException("MyHttpHandler cannot process requests.");
      }

      public bool IsReusable
      {
         // IsReusable must be set to false since class has a member!
         get { return false; }
      }
   }
}

8
!MS应该解决这一问题...如果我标志着一个模块实现IRequiresSessionState,我不应该跳通箍得到它...(性感的代码确实)
BigBlondeViking

6
好的代码。我以为我会需要这个,但事实证明并非如此。此代码最终为通过服务器的每个图像和其他非页面资源加载会话。就我而言,我只是检查PostAcquireRequestState事件中的session是否为null,如果为空则返回。
Abtin Forouzandeh,2010年

7
如果请求的资源不处理会话状态,则此代码很有用。对于标准.aspx页面,只需添加您的代码即可访问PostAcquireRequestState事件处理程序上的会话。会话状态在任何BeginRequest事件处理程序上将不可用,因为尚未获取会话状态。
JCallico 2010年

3
就我而言,它不起作用。我得到“会话状态在此上下文中不可用”。当有尝试访问静态文件的请求时。有什么帮助吗?
maxisam

3
为了使此功能可以处理静态文件,我还需要通过删除preCondition =“ managedHandler”(<remove name =“ Session” /> <add name =“会话”“ type =“ System.Web.SessionState.SessionStateModule” />)
nlips

39

假设您的HTTP模块不处理在初始化会话状态之前发生的任何管道事件,则HttpContext.Current.Session应该可以正常工作。

编辑,在注释中得到澄清:处理BeginRequest事件时,Session对象实际上仍然为null / Nothing,因为它尚未由ASP.NET运行时初始化。要解决此问题,请将您的处理代码移到PostAcquireRequestState之后发生的事件中-我自己喜欢PreRequestHandlerExecute,因为在此阶段几乎所有低级工作都已完成,但您仍会抢占任何常规处理。


不幸的是,这在HTTPModule中不可用-“对象引用未设置为对象的实例。”
克里斯·罗伯茨

我正在处理“ OnBeginRequest”吗?
克里斯·罗伯茨

感谢更新。如果我在应用程序级别的事件中处理它,为什么不只在应用程序级别上进行所有处理,而不使用HTTPModule?
克里斯·罗伯茨

1
PostAcquireRequeststate不是“应用程序级事件”:例如,如果HTTP请求是由Web服务处理程序处理的,则您仍会在HTTP模块中看到它,但在Global.asax中却看不到...
mdb

这对我来说似乎并不可靠。以下代码通常会导致异常“在此上下文中会话状态不可用”。实际上,它使VS调试器崩溃非常明显。context.PreRequestHandlerExecute + =(发送方,args)=> Console.Write((((HttpApplication)sender).Session [“ test”] ;;
cbp

15

可以在处理程序中访问HttpContext.Current.Sessionin 。IHttpModulePreRequestHandlerExecute

PreRequestHandlerExecute:“在ASP.NET开始执行事件处理程序(例如,页面或XML Web服务)之前发生。” 这意味着在提供“ aspx”页面之前,将执行此事件。“会话状态”可用,因此您可以自行淘汰。

例:

public class SessionModule : IHttpModule 
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += BeginTransaction;
            context.EndRequest += CommitAndCloseSession;
            context.PreRequestHandlerExecute += PreRequestHandlerExecute;
        }



        public void Dispose() { }

        public void PreRequestHandlerExecute(object sender, EventArgs e)
        {
            var context = ((HttpApplication)sender).Context;
            context.Session["some_sesion"] = new SomeObject();
        }
...
}

我尝试过,您确实可以参加会议。但似乎RequestHeader并不完整,尤其是HeaderContentType
MatthiasMüller

12

如果要在托管应用程序中编写一个普通的基本HttpModule,并希望通过页面或处理程序将其应用于asp.net请求,则只需确保在会话创建后的生命周期中使用一个事件即可。通常我要去PreRequestHandlerExecute而不是Begin_Request。mdb在其编辑中具有正确的权限。

最初列出来回答问题的较长代码段有效,但比初始问题复杂且范围更广。当内容来自没有ASP.net处理程序的内容时,它将处理这种情况,您可以在其中实现IRequiresSessionState接口,从而触发会话机制使其可用。(就像磁盘上的静态gif文件一样)。基本上是设置一个虚拟处理程序,然后仅实现该接口以使会话可用。

如果您只想使用代码会话,则只需在模块中选择要处理的正确事件即可。


0

尝试一下:在类MyHttpModule中声明:

private HttpApplication contextapp;

然后:

public void Init(HttpApplication application)
{
     //Must be after AcquireRequestState - the session exist after RequestState
     application.PostAcquireRequestState += new EventHandler(MyNewEvent);
     this.contextapp=application;
}  

因此,在同一类的另一个方法(事件)中:

public void MyNewEvent(object sender, EventArgs e)
{
    //A example...
    if(contextoapp.Context.Session != null)
    {
       this.contextapp.Context.Session.Timeout=30;
       System.Diagnostics.Debug.WriteLine("Timeout changed");
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.