Http Module無法存取Session的問題

在某些情況下,要實作一個每次Http Request都會執行,且若為WebForm .aspx其運行優先權還要超越的Page_Load事件,更還要可支援Session的存取,這時候只有實作HTTP Module可以達成。

通常要實作IHttpModule可以透過簡單的「global.asax」或是較複雜的「web.config之modules掛載」來達成,而這兩者其實都是殊途同歸的,只是ASP.NET留下一條客製化IHttpModule的道路讓程式設計師實作,官方文件於此: HttpApplication Class

典型的IHttpModule之C#實作

程式碼大致上如下:

namespace Slashview
{
  public class HttpRequestInitial : System.Web.IHttpModule
  { 
    public void Init(System.Web.HttpApplication oContext)
    { oContext.BeginRequest += OnBeginRequest; }

    public void Dispose()  { }

    //每個HttpRequest都會跑一次
    private void OnBeginRequest(object sender, System.EventArgs e)
    { //在ASPX頁面的Page_Load之前先執行你想要的程式碼
    }
  }
}

有了上面的程式碼架構,我們再把它放到web.config中就可以進行啟動。

<?xml version="1.0"?>
<configuration>
  <system.webServer>
    <modules>
      <add name="HttpRequestInitial" type="Slashview.HttpRequestInitial"/>
    </modules>
  </system.webServer>
</configuration>

以global.asax的觀點來說就更簡單了,按照上面的程式碼寫對應只要寫在Application_BeginRequest方法中即可。

private void Application_BeginRequest(object sender, EventArgs e)
{
  //在ASPX頁面的Page_Load之前先執行你想要的程式碼
}

大家可以觀察到在客製化的IHttpModule中,自定義的OnBeginRequest方法是掛載在BeginRequest委派下,而這個BeginRequest委派正是global.asax的Application_BeginRequest,兩者是等效的。

存取Session永遠為null的問題

然而當你試圖在上述的程式碼中存取Session(System.Web.HttpContext.Current.Session),卻發現ASP.NET會拋給你null(Nothing),這一切的原因是因為在這個事件觸發的時期Session根本還沒有準備好,所以你無法存取Session。

我們可以看一下官方文件:ASP.NET HTTP modules and HTTP handlers

由上方的文件可得知HttpApplication(Http Module)觸發事件的順序(生命週期)分別如下:

1.  BeginRequest
2.  AuthenticateRequest
3.  AuthorizeRequest
4.  ResolveRequestCache
5.  AcquireRequestState
6.  PreRequestHandlerExecute
7.  PostRequestHandlerExecute
8.  ReleaseRequestState
9.  UpdateRequestCache
10.  EndRequest

大家可以在官方文件中看到AcquireRequestState事件的描述如下:

AcquireRequestState: Session state is retrieved from the state store. If you want to build your own state management module, synchronize this event to grab the session state from your state store.

換句話說,也就是Session到AcquireRequestState時期才開始被喚醒,為了更安全更不複雜的操控Session,建議在PreRequestHandlerExecute再來運行Session的操作是最安全的。

結論

若要操作Session,建議綁定PreRequestHandlerExecute事件為佳。

HttpModule IHttpModule Events EventDelegate LifeCycles 生命週期 Session Null Nothing Exception CanNotAccess