項目中httpModules應用:
WapModule.cs:
public class WapModule:IHttpModule { public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(context_BeginRequest); } // 處理BeginRequest 事件的實際代碼 void context_BeginRequest(object sender, EventArgs e) { ...............//todo:進入首頁前的處理代碼
//eg:獲得上下文
//HttpApplication application = (HttpApplication)sender;
//HttpContext context = application.Context;
} public void Dispose() { } }
Web.config:
<system.web>
<httpModules>
<add name="MyModule" type="myWeb.WapModule"/>
</httpModules>
</system.web>
這樣假設將網站的首頁設置為Default.aspx,訪問Default.aspx頁面時,在進入Default.aspx頁面的代碼之前會先進入WapModule.cs,然后根據WapModule.cs中的代碼動態跳轉到制定首頁及記錄一些訪問者的機器信息等操作;
==============分割線======================
技術點:
(一)ASP.NET對請求處理的過程:
當請求一個*.aspx文件的時候,這個請求會被inetinfo.exe進程截獲,它判斷文件的后綴(aspx)之后,將這個請求轉交給ASPNET_ISAPI.dll,ASPNET_ISAPI.dll會通過http管道(Http PipeLine)將請求發送給ASPNET_WP.exe進程,在ASPNET_WP.exe進程中通過HttpRuntime來處理這個請求,處理完畢將結果返回客戶端。
inetinfo.exe進程:是www服務的進程,IIS服務和ASPNET_ISAPI.DLL都寄存在此進程中。
ASPNET_ISAPI.DLL:是處理.aspx文件的win32組件。其實IIS服務器是只能識別.html文件的,當IIS服務器發現被請求的文件是.aspx文件時,IIS服務器將其交給aspnet_isapi.dll來處理。
aspnet_wp.exe進程:ASP.NET框架進程,提供.net運行的托管環境,.net的CLR(公共語言運行時)就是寄存在此進程中。
ASP.NET Framework處理一個Http Request的流程:
HttpRequest-->inetinfo.exe-->ASPNET_ISAPI.dll-->ASPNET_WP.exe-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()
ASP.NET請求處理過程是基於管道模型的,這個管道模型是由多個HttpModule和HttpHandler組成,ASP.NET把http請求依次傳遞給管道中各個HttpModule,最終被HttpHandler處理,處理完成后,再次經過管道中的HTTP模塊,把結果返回給客戶端。我們可以在每個HttpModule中都可以干預請求的處理過程。

注意:在http請求的處理過程中,只能調用一個HttpHandler,但可以調用多個HttpModule。
(二)HttpModule
httpModules作用:
當請求到達HttpModule的時候,系統還沒有對這個請求真正處理,但是我們可以在這個請求傳遞到處理中心(HttpHandler)之前附加一些其它信息,或者截獲的這個請求並作一些額外的工作,也或者終止請求等。在HttpHandler處理完請求之后,我們可以再在相應的HttpModule中把請求處理的結果進行再次加工返回客戶端。
HTTP模塊是實現了System.Web.IhttpModule接口的類。
IHttpModule接口的聲明:
public interface IHttpModule
{
void Init (HttpApplication context);
void Dispose ();
}
Init 方法:系統初始化的時候自動調用,這個方法允許HTTP模塊向HttpApplication 對象中的事件注冊自己的事件處理程序。
Dispose方法: 這個方法給予HTTP模塊在對象被垃圾收集之前執行清理的機會。此方法一般無需編寫代碼。
HTTP模塊可以向System.Web.HttpApplication對象注冊下面一系列事件:
AcquireRequestState 當ASP.NET運行時准備好接收當前HTTP請求的對話狀態的時候引發這個事件。
AuthenticateRequest 當ASP.NET 運行時准備驗證用戶身份的時候引發這個事件。
AuthorizeRequest 當ASP.NET運行時准備授權用戶訪問資源的時候引發這個事件。
BeginRequest 當ASP.NET運行時接收到新的HTTP請求的時候引發這個事件。
Disposed 當ASP.NET完成HTTP請求的處理過程時引發這個事件。
EndRequest 把響應內容發送到客戶端之前引發這個事件。
Error 在處理HTTP請求的過程中出現未處理異常的時候引發這個事件。
PostRequestHandlerExecute 在HTTP處理程序結束執行的時候引發這個事件。
PreRequestHandlerExecute 在ASP.NET開始執行HTTP請求的處理程序之前引發這個事件。在這個事件之后,ASP.NET 把該請求轉發給適當的HTTP處理程序。
PreSendRequestContent 在ASP.NET把響應內容發送到客戶端之前引發這個事件。這個事件允許我們在內容到達客戶端之前改變響應內容。我們可以使用這個事件給頁面輸出添加用於所有頁面的內容。例如通用菜單、頭信息或腳信息。
PreSendRequestHeaders 在ASP.NET把HTTP響應頭信息發送給客戶端之前引發這個事件。在頭信息到達客戶端之前,這個事件允許我們改變它的內容。我們可以使用這個事件在頭信息中添加cookie和自定義數據。
ReleaseRequestState 當ASP.NET結束所搜有的請求處理程序執行的時候引發這個事件。
ResolveRequestCache 我們引發這個事件來決定是否可以使用從輸出緩沖返回的內容來結束請求。這依賴於Web應用程序的輸出緩沖時怎樣設置的。
UpdateRequestCache 當ASP.NET完成了當前的HTTP請求的處理,並且輸出內容已經准備好添加給輸出緩沖的時候,引發這個事件。這依賴於Web應用程序的輸出緩沖是如何設置的。
上面這么多的事件,我們看起來可能會有些眼暈,但沒關系,下面一步一步地看。
HttpModule生命周期示意圖

下面是事件的觸發順序:

BeginRequest和PreRequestHandlerExecute之間的事件是在服務器執行HttpHandler處理之前觸發。
PostRequestHandlerExecute和PreSendRequestContent之間的事件是在服務器執行Handler處理之后觸發。
(三)下面我們看一下如何使用HttpModule來實現我們日常的應用:
HttpModule通過在某些事件中注冊,把自己插入ASP.NET請求處理管道。當這些事件發生的時候,ASP.NET調用對相應的HTTP模塊,這樣該模塊就能處理請求了。
1、向每個頁面動態添加一些備注或說明性的文字:
有的網站每一個頁面都會彈出一個廣告或在每個頁面都以注釋形式(<!-- -->)加入網站的版權信息。如果在每個頁面教編寫這樣的JS代碼的話,對於大一點的網站,這種JS代碼的編寫與維護可是一個很繁瑣枯燥的工作。
有了HttpModule我們就可以很簡單地解決這個問題了。HttpModule是客戶端發出請求到客戶端接收到服務器響應之間的一段必經之路。我們完全可以在服務器處理完請求之后,並在向客戶端發送響應文本之前這段時機,把這段注釋文字添加到頁面文本之后。這樣,每一個頁面請求都會被附加上這段注釋文字。
這段代碼究竟該在哪個事件里實現呢? PostRequestHandlerExecute和PreSendRequestContent之間的任何一個事件都可以,但我比較喜歡在EndRequest事件里編寫代碼。
第一步:創建一個類庫ClassLibrary831。
第二步:編寫一個類實現IHttpModule接口
class TestModule:IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
}
}
第三步:在Init事件中注冊EndRequest事件,並實現事件處理方法
class TestModule:IHttpModule
{
public void Dispose(){}
public void Init(HttpApplication context)
{
context.EndRequest += new EventHandler(context_EndRequest);
}
void context_EndRequest(object sender, EventArgs e)
{
HttpApplication ha = (HttpApplication)sender;
ha.Response.Write("<!--這是每個頁面都會動態生成的文字。--grayworm-->");
}
}
第四步:在Web.Conofig中注冊一下這個HttpModule模塊
<httpModules>
<add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
</httpModules>
name:模塊名稱,一般是類名
type:有兩部分組成,前半部分是命名空間和類名組成的全名,后半部分是程序集名稱,如果類是直接放在App_Code文件夾中,那程序名稱是App_Code。
這樣在Web站點是添加該類庫的引用后,運行每個頁面,會發現其源文件中都會加入“<!--這是每個頁面都會動態生成的文字。--grayworm-->”這句話。同樣的方法你也可以在其中加入JS代碼。
2、身份檢查
大家在作登錄時,登錄成功后,一般要把用戶名放在Session中保存,在其它每一個頁面的Page_Load事件中都檢查Session中是否存在用戶名,如果不存在就說明用戶未登錄,就不讓其訪問其中的內容。
在比較大的程序中,這種做法實在是太笨拙,因為你幾乎要在每一個頁面中都加入檢測Session的代碼,導致難以開發和維護。下面我們看看如何使用HttpModule來減少我們的工作量
由於在這里我們要用到Session中的內容,我們只能在AcquireRequestState和PreRequestHandlerExecute事件中編寫代碼,因為在HttpModule中只有這兩事件中可以訪問Session。這里我們選擇PreRequestHandlerExecute事件編寫代碼。
第一步:創建一個類庫ClassLibrary831。
第二步:編寫一個類實現IHttpModule接口
class TestModule:IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
}
}
第三步:在Init事件中注冊PreRequestHandlerExecute事件,並實現事件處理方法
class AuthenticModule:IHttpModule { public void Dispose(){} public void Init(HttpApplication context) { context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute); } void context_PreRequestHandlerExecute(object sender, EventArgs e) { HttpApplication ha = (HttpApplication)sender; string path = ha.Context.Request.Url.ToString(); int n = path.ToLower().IndexOf("Login.aspx"); if (n == -1) //是否是登錄頁面,不是登錄頁面的話則進入{} { if (ha.Context.Session["user"] == null) //是否Session中有用戶名,若是空的話,轉向登錄頁。 { ha.Context.Response.Redirect("Login.aspx?source=" + path); } } } }
第四步:在Login.aspx頁面的“登錄”按鈕中加入下面代碼
protected void Button1_Click(object sender, EventArgs e) { if(true) //判斷用戶名密碼是否正確 { if (Request.QueryString["source"] != null) { string s = Request.QueryString["source"].ToLower().ToString(); //取出從哪個頁面轉來的 Session["user"] = txtUID.Text; Response.Redirect(s); //轉到用戶想去的頁面 } else { Response.Redirect("main.aspx"); //默認轉向main.aspx } } }
第五步:在Web.Conofig中注冊一下這個HttpModule模塊
<httpModules>
<add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
</httpModules>
3、多模塊的操作
如果定義了多個HttpModule,在web.config文件中引入自定義HttpModule的順序就決定了多個自定義HttpModule在處理一個HTTP請求的接管順序。

