簡體   English   中英

我可以從 HTTPModule 訪問會話狀態嗎?

[英]Can I access session state from an HTTPModule?

我真的可以從我的 HTTPModule 中更新用戶的會話變量,但從我所見,這是不可能的。

更新:我的代碼當前正在OnBeginRequest ()事件處理程序中運行。

更新:根據到目前為止收到的建議,我嘗試將其添加到 HTTPModule 中的Init ()例程中:

AddHandler context.PreRequestHandlerExecute, AddressOf OnPreRequestHandlerExecute

但是在我的OnPreRequestHandlerExecute例程中,會話狀態仍然不可用!

謝謝,如果我遺漏了什么,我深表歉意!

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

HttpContext.Current.Session應該可以正常工作,假設您的 HTTP 模塊沒有處理在會話狀態被初始化之前發生的任何管道事件......

編輯,在注釋中澄清后:處理BeginRequest 事件時,Session 對象確實仍然為 null/Nothing,因為它還沒有被 ASP.NET 運行時初始化。 要解決此問題,請將您的處理代碼移至PostAcquireRequestState之后發生的事件——我自己喜歡PreRequestHandlerExecute ,因為在此階段幾乎完成了所有低級工作,但您仍然搶占了任何正常處理。

可以在PreRequestHandlerExecute處理程序中訪問IHttpModuleHttpContext.Current.Session

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

如果您要在托管應用程序中編寫一個普通的基本 HttpModule,並希望通過頁面或處理程序應用於 asp.net 請求,則只需確保在會話創建后的生命周期中使用事件。 PreRequestHandlerExecute 而不是 Begin_Request 通常是我去的地方。 mdb 在他的編輯中是正確的。

最初列為回答問題的較長代碼片段有效,但比最初的問題復雜和廣泛。 當內容來自沒有可用的 ASP.net 處理程序的內容時,它將處理這種情況,您可以在其中實現 IRequiresSessionState 接口,從而觸發會話機制使其可用。 (就像磁盤上的靜態 gif 文件)。 它基本上是設置一個虛擬處理程序,然后只實現該接口以使會話可用。

如果您只需要代碼的會話,只需選擇要在模塊中處理的正確事件。

試試看:在 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");
    }
}

從 .NET 4.0 開始,不需要使用 IHttpHandler 進行此 hack 加載會話狀態(就像最受好評的答案中的那樣)。 有一個方法HttpContext.SetSessionStateBehavior來定義所需的會話行為。 如果所有請求都需要 Session,請在 web.config HttpModule 聲明中將runAllManagedModulesForAllRequests設置為 true,但請注意,為所有請求運行所有模塊會產生顯着的性能成本,因此請確保使用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()
        {
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM