87

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

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

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

AddHandler context.PreRequestHandlerExecute, AddressOf OnPreRequestHandlerExecute

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

谢谢,如果我遗漏了什么,我们深表歉意!

4

6 回答 6

84

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; }
      }
   }
}
于 2008-11-09T19:44:25.963 回答
39

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

编辑,在注释中澄清后:在处理BeginRequest 事件时,Session 对象确实仍然是 null/Nothing,因为它还没有被 ASP.NET 运行时初始化。要解决此问题,请将您的处理代码移至PostAcquireRequestState之后发生的事件——我自己喜欢PreRequestHandlerExecute,因为所有低级工作都在此阶段完成,但您仍然抢占任何正常处理。

于 2008-11-09T19:35:52.890 回答
15

访问HttpContext.Current.Sessionin aIHttpModule可以在PreRequestHandlerExecute处理程序中完成。

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();
        }
...
}
于 2011-09-13T10:56:31.533 回答
12

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

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

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

于 2009-06-02T21:15:14.410 回答
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");
    }
}
于 2015-05-18T18:16:10.767 回答
0

由于 .NET 4.0 没有必要使用 IHttpHandler 来加载会话状态(就像最受好评的答案中的一个)。有一个方法HttpContext.SetSessionStateBehavior来定义所需的会话行为。如果在 web.config HttpModule 声明中设置为 true 的所有请求都需要 Session ,但请注意,为所有请求运行所有模块会产生巨大的性能成本,因此如果您不需要所有请求的 Session,请runAllManagedModulesForAllRequests务必使用。preCondition="managedHandler"对于未来的读者,这里有一个完整的例子:

web.config 声明 - 为所有请求调用 HttpModule:

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
        <add name="ModuleWithSessionAccess" type="HttpModuleWithSessionAccess.ModuleWithSessionAccess, HttpModuleWithSessionAccess"/>
    </modules>
</system.webServer>

web.config 声明 - 仅为托管请求调用 HttpModule:

<system.webServer>
    <modules>
        <add name="ModuleWithSessionAccess" type="HttpModuleWithSessionAccess.ModuleWithSessionAccess, HttpModuleWithSessionAccess" preCondition="managedHandler"/>
    </modules>
</system.webServer>

IHttpModule 实现:

namespace HttpModuleWithSessionAccess
{
    public class ModuleWithSessionAccess : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += Context_BeginRequest;
            context.PreRequestHandlerExecute += Context_PreRequestHandlerExecute;
        }

        private void Context_BeginRequest(object sender, EventArgs e)
        {
            var app = (HttpApplication)sender;
            app.Context.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
        }
    
        private void Context_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            var app = (HttpApplication)sender;
            if (app.Context.Session != null)
            {
                app.Context.Session["Random"] = $"Random value: {new Random().Next()}";
            }
        }

        public void Dispose()
        {
        }
    }
}
于 2021-06-07T19:59:22.760 回答