引言
Http 請求處理流程和Http Handler 介紹這兩篇文章里,我們首先了解了Http請求在服務(wù)器端的處理流程,隨后我們知道Http請求最終會由實現(xiàn)了IHttpHandler接口的類進(jìn)行處理(應(yīng)該記得Page類實現(xiàn)了IHttpHandler)。從Http 請求處理流程一文的最后的一幅圖中可以看到,在Http請求由IHttpHandler處理之前,它需要通過一系列的Http Module;在請求處理之后,它需要再次通過一系列的Http Module,那么這些Http Module是如何組成的?用來做什么呢?本文將對Http Module作以介紹。
Http Module概述
暫時先不考慮我們自己實現(xiàn)Http Module的情況。在.Net中,Http Module 是實現(xiàn)了IHttpModule接口的程序集。IHttpModule 接口本身并沒有什么好大寫特寫的,由它的名字可以看出,它不過是一個普普通通的接口而已。實際上,我們關(guān)心的是實現(xiàn)了這些接口的類,如果我們也編寫代碼實現(xiàn)了這個接口,那么有什么用途。一般來說,我們可以將Asp.Net中的事件分成三個級別,最頂層是 應(yīng)用程序級事件、其次是頁面級事件、最下面是控件級事件,事件的觸發(fā)分別與 應(yīng)用程序周期、頁面周期、控件周期緊密相關(guān)。而 Http Module 的作用是與應(yīng)用程序事件密切相關(guān)的。
我們通過Http Module在Http請求管道(Pipeline)中注冊期望對應(yīng)用程序事件做出反應(yīng)的方法,在相應(yīng)的事件觸發(fā)的時候(比如說BeginRequest事件,它在應(yīng)用程序收到一個Http請求并即將對其進(jìn)行處理時觸發(fā)),便會調(diào)用Http Module注冊了的方法,實際的工作在這些方法中執(zhí)行。.Net 本身已經(jīng)有很多的Http Module,其中包括 表單驗證Module(FormsAuthenticationModule), session 狀態(tài)Module(SessionStateModule),輸出緩存Module (OutputCacheModule)等。
注冊 Http Module
在注冊我們自己編寫的 Http Module 之前,先來看看Asp.Net中已經(jīng)有的HttpModule。與 Http Handler類似,我們需要打開機器上C:/WINDOWS/Microsoft.NET/Framework/ v2.0.50727/CONFIG 目錄下的 web.config 文件。找到 <httpModules/> 結(jié)點,應(yīng)該可以看到下面的內(nèi)容:
<httpModules> <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" /> <add name="Session" type="System.Web.SessionState.SessionStateModule" /> <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" /> <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" /> <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" /> <add name="RoleManager" type="System.Web.Security.RoleManagerModule" /> <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />... 略</httpModules>
我們先從結(jié)點上看,type屬性與上一節(jié)所說的http handler結(jié)點的type屬性類似,都代表了相應(yīng)的程序集。但是,與http handler 不同,module只提供了一個name屬性,沒有諸如 path這樣指定某一特定(或者用通配符 * 代表某一種類)文件的處理程序。這是與Module的特點相關(guān)的,我們知道 module 是響應(yīng)應(yīng)用程序周期中觸發(fā)的事件,對于所有提交到aspnet_isapi.dll的請求都一樣,即便請求只是像類似http://www.tracefact.net/images/logo.gif 這樣獲取一張圖片而已(對ISAPI進(jìn)行過設(shè)置以后,默認(rèn)aspnet_isapi.dll不接手圖片文件)。
與Http handler類似,在這冊我們自己的http module 時,假設(shè)類名為ModuleDemo,位于myNameSpace命名空間下,程序集名稱為myDll,我們只需將myDll.dll拷貝到Bin目錄下,并在站點的 web.config 文件 system.web 結(jié)點下創(chuàng)建 httpModules 結(jié)點:
<system.web> <httpModules> <add name="CustomModuleName" type="myNameSpace.ModuleDemo, myDll"/> </httpModules></system.web>
type屬性由分號“,”分為兩部分,前面是命名空間及類名,也就是類型名;后面是程序集名。如果我們將代碼創(chuàng)建在App_Code目錄中,則不需要再指定程序集名。
name屬性由我們自己命名,不一定與類名相同,此處我將它命名為“CustomModuleName”。我們可以通過應(yīng)用程序(Httpapplication)的Modules屬性獲取HttpModuleCollection集合,然后通過name屬性,進(jìn)一步獲取HttpModule對象。
通過name屬性,我們還可以在global.asax中文件中編寫自定義HttpModule暴露出的事件的處理程序,它采用的格式是:void ModuleName_EventName(object sender, EventArgs e)。我們將在后面做更詳細(xì)介紹。
Asp.Net 內(nèi)置的 Http Modules
下面這張表格列出了C:/WINDOWS/Microsoft.NET/Framework/ v2.0.50727/CONFIG下的Web.Config中的 Asp.Net 內(nèi)置的Http Modules 及其主要作用。
名稱 | 類型 | 功能 |
OutputCache | System.Web.Caching.OutputCacheModule | 頁面級輸出緩存 |
Session | System.Web.SessionState.SessionStateModule | Session狀態(tài)管理 |
WindowsAuthentication | System.Web.Security.WindowsAuthenticationModule | 用集成Windows身份驗證進(jìn)行客戶端驗證 |
FormsAuthentication | System.Web.Security.FormsAuthenticationModule | 用基于Cookie的窗體身份驗證進(jìn)行客戶端身份驗證 |
PassportAuthentication | System.Web.Security.PassportAuthenticationModule | 用MS護(hù)照進(jìn)行客戶身份驗證 |
RoleManager | System.Web.Security.RoleManagerModule | 管理當(dāng)前用戶角色 |
UrlAuthorization | System.Web.Security.UrlAuthorizationModule | 判斷用戶是否被授權(quán)訪問某一URL |
FileAuthorization | System.Web.Security.FileAuthorizationModule | 判斷用戶是否被授權(quán)訪問某一資源 |
AnonymousIdentification | System.Web.Security.AnonymousIdentificationModule | 管理Asp.Net應(yīng)用程序中的匿名訪問 |
PRofile | System.Web.Profile.ProfileModule | 管理用戶檔案文件的創(chuàng)立 及相關(guān)事件 |
ErrorHandlerModule | System.Web.Mobile.ErrorHandlerModule | 捕捉異常,格式化錯誤提示字符,傳遞給客戶端程序 |
我們將在后面用編程的方式來查看它。
IHttpModule接口
看了這么多理論知識,本節(jié)將開始動手寫點程序,實現(xiàn)自己的Http Module。我們首先需要看下IHttpModule 接口,它包括下面兩個方法:
public void Init(HttpApplication context);public void Dispose();
Init():這個方法接受一個HttpApplication對象,HttpApplication代表了當(dāng)前的應(yīng)用程序,我們需要在這個方法內(nèi)注冊 HttpApplication對象暴露給客戶端的事件。可見,這個方法僅僅是用來對事件進(jìn)行注冊,而實際的事件處理程序,需要我們另外寫方法。
整個過程很好理解:
NOTE:如果你不了解事件注冊等相關(guān)內(nèi)容,請參閱C#中的委托與事件一文。
Dispose():它可以在進(jìn)行垃圾回收之前進(jìn)行一些清理工作。
綜上所述:實現(xiàn)一個 IHttpModule 的模板一般是這樣的:
public class ModuleDemo:IHttpModule{ public void Init(HttpApplication context) { // 注冊HttpApplication應(yīng)用程序 BeginRequest 事件 // 也可以是其他任何HttpApplication暴露出的事件 context.BeginRequest += new EventHandler(context_BeginRequest); } void context_BeginRequest(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; HttpContext context = application.Context; // 做些實際的工作,HttpContext對象都獲得了,剩下的基本可以自由發(fā)揮了 } public void Dispose() { }}
通過Http Module向Http請求輸出流中寫入文字
本例中,我們僅用BeginRequest事件和 EndRequest 事件對 Http Module 的使用作以說明。我們通過這個范例,了解 Http Module 基本的使用方法。
首先,請創(chuàng)建一個新的站點,在App_Code目錄中添加類文件: ModuleDemo.cs:
public class ModuleDemo:IHttpModule{ // Init方法僅用于給期望的事件注冊方法 public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(context_BeginRequest); context.EndRequest += new EventHandler(context_EndRequest); } // 處理BeginRequest 事件的實際代碼 void context_BeginRequest(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; HttpContext context = application.Context; context.Response.Write("<h1 style='color:#00f'>來自HttpModule 的處理,請求到達(dá)</h1><hr>"); } // 處理EndRequest 事件的實際代碼 void context_EndRequest(object sender, EventArgs e) { HttpApplication application = (HttpApplication)sender; HttpContext context = application.Context; context.Response.Write("<hr><h1 style='color:#f00'>來自HttpModule的處理,請求結(jié)束</h1>"); } public void Dispose() { }}
上面的代碼很簡單,它注冊了 HttpApplication實例的 BeginRequest 事件
新聞熱點
疑難解答