實現IHttpModule接口獲取Session來實現頁面訪問日誌功

我們在開發企業Web應用程序時經常需要對用戶的操作記錄日誌,以便在發生突發事件後有據可查,比如要對用戶訪問的每一個頁面都做日誌記錄。通常的做法可能是編寫一個記錄日誌的方法(如:AddAccessLog),在每一個頁面的Page_Load事件中調用這個AddAccessLog方法,從而達到記錄頁面訪問日誌的目的。這樣的方法在頁面較少的時候可行,但是當項目變得越來越大,需要記錄日誌的頁面越來越多的時候,我們要在每個頁面中都調用這樣的方法,從而使得系統很難維護。有沒有簡單一點的辦法呢,何不用IHttpModule接口實現一個自定義的LogHttpModule來試試呢?

IHttpModule接口中定義了兩個方法:Init和Dispose。Init方法初始化一個模塊,併爲它做好處理請求的準備。這時,我們同意接受感興趣的事件通知。Dispose方法處置該模塊使用資源。Init方法接受一個服務該請求的HttpApplication對象的引用。使用該引用可以連接到系統事件。

class PageLoggerModule : IHttpModule  //實現IHttpModule接口
{

public void Dispose()
{
}

public void Init(HttpApplication context)
{
    context.BeginRequest += new EventHandler(context_BeginRequest);
}

void context_BeginRequest(object sender, EventArgs e)
{

//在這裏實現具體代碼

HttpApplication app = (HttpApplication)sender;
HttpContext ctx = app.Context;

//acquire session state
string userId = "Not Registered";
if (ctx.Session != null && ctx.Session["userId"] != null)
{
    userId = ctx.Session["userId"].ToString();
}

//acquire request string
string funcId = "Init funcId";
if (ctx.Request.QueryString["funcId"] != null)
{
    funcId = ctx.Request.QueryString["funcId"].ToString();
}

LogEntry log = new LogEntry(); // 這裏是自定義的一個類,屬性列表和數據庫中的字段一致
log.DateTime = System.DateTime.Now;
log.IpAddress = ctx.Request.UserHostAddress;
log.MachineName = ctx.Request.UserHostName;
log.UserId = userId;
log.FunctionId = funcId;

string logString = log.DateTime.ToString() + "<br/>"
+ log.UserId + "<br/>"
+ log.IpAddress + "<br/>"
+ log.MachineName + "<br/>"
+ log.FunctionId + "<br/>";

//you can add other codes here
ctx.Response.AppendHeader("Author", "Changyu Du");

ctx.Response.Write(logString);

}

}

在Web.config中,System.Web節中增加一個HttpModule:

    <httpModules>
       <add name="PageLoggerHttpModule" type="PageLoggerHttpModule.PageLoggerModule,PageLoggerHttpModule"/>
    </httpModules>

新建一個普通的aspx頁面,在頁面加載時把用戶信息保存到Session中,模擬一下項目應用中的情形:

protected void Page_Load(object sender, EventArgs e)
{
    //Add userName into SESSION
    if (Session["userId"] == null)
    {
        Session["userId"] = "1101";
    }
    else
    {
        Response.Write("SESSION :userId = "+Session["userId"].ToString());
    }
}

爲了確保把用戶Id信息加入到session中,測試頁面上還隨便加了個button,button_click什麼都不幹,就是爲了讓頁面回發一下確保把userId存入到Session中去。F5運行一下,嗯,不錯,LogEntry的信息都輸出出來了,已經取得了訪問時間,IP地址之類的信息,基本成功!下來直接把LogEntry的信息保存到數據庫就OK了。

可是,別忙,怎麼總取不到Session中的用戶信息呢?記錄訪問日誌用戶Id這樣的信息肯定是需要記錄的啊!

後來放狗一搜才發現,還是對aspnet的事件處理流程不理解,Begin_Request時還沒有加載Session狀態呢,自然就取不到了。

下面是MSDN上提供的事件觸發順序:

在處理該請求時將由 HttpApplication 類執行以下事件。希望擴展 HttpApplication 類的開發人員尤其需要注意這些事件。

  1. 對請求進行驗證,將檢查瀏覽器發送的信息,並確定其是否包含潛在惡意標記。有關更多信息,請參見 ValidateRequest腳本侵入概述

  2. 如果已在 Web.config 文件的 UrlMappingsSection 節中配置了任何 URL,則執行 URL 映射。

  3. 引發 BeginRequest 事件。

  4. 引發 AuthenticateRequest 事件。

  5. 引發 PostAuthenticateRequest 事件。

  6. 引發 AuthorizeRequest 事件。

  7. 引發 PostAuthorizeRequest 事件。

  8. 引發 ResolveRequestCache 事件。

  9. 引發 PostResolveRequestCache 事件。

  10. 根據所請求資源的文件擴展名(在應用程序的配置文件中映射),選擇實現 IHttpHandler 的類,對請求進行處理。如果該請求針對從 Page 類派生的對象(頁),並且需要對該頁進行編譯,則 ASP.NET 會在創建該頁的實例之前對其進行編譯。

  11. 引發 PostMapRequestHandler 事件。

  12. 引發 AcquireRequestState 事件。

  13. 引發 PostAcquireRequestState 事件。

  14. 引發 PreRequestHandlerExecute 事件。

  15. 爲該請求調用合適的 IHttpHandler 類的 ProcessRequest 方法(或異步版 BeginProcessRequest)。例如,如果該請求針對某頁,則當前的頁實例將處理該請求。

  16. 引發 PostRequestHandlerExecute 事件。

  17. 引發 ReleaseRequestState 事件。

  18. 引發 PostReleaseRequestState 事件。

  19. 如果定義了 Filter 屬性,則執行響應篩選。

  20. 引發 UpdateRequestCache 事件。

  21. 引發 PostUpdateRequestCache 事件。

  22. 引發 EndRequest 事件。

AcquireRequestState事件,當實際服務請求的處理程序獲得與該請求關聯的狀態信息時發生。在這個事件發生時才能取到Session中是userId信息。BeginRequest事件在AcquireRequestState之前發生,我們把取Session狀態的代碼放在BeginRequest中肯定是取不到的。

問題找到了,把日誌記錄代碼放在AcquireRequestState中就可以了,於是改成下面的樣子:

public void Init(HttpApplication context)
{
    context.AcquireRequestState += new EventHandler(context_AcquireRequestState);
}

void context_AcquireRequestState(object sender, EventArgs e)
{

  //原先context_BeginRequest中的代碼,不重複貼佔地方了 :)

//把LogEntry中的信息保存到數據庫

}

好了,這樣我們繼承了IHttpModule接口,實現了一個自定義的LogMudule,這樣在用戶方面每個頁面時,都會自動記錄用戶的信息記如訪問日誌數據庫中,再也不用到每個頁面的Page_Load中去寫了,維護起來也方便多了

發佈了86 篇原創文章 · 獲贊 0 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章