Http 請求處理流程 和 Http Handler 介紹 這兩篇文章裏,咱們首先了解了Http請求在服務器端的處理流程,隨後咱們知道Http請求最終會由實現了IHttpHandler接口的類進行處理(應該記得Page類實現了IHttpHandler)。從 Http 請求處理流程 一文的最後的一幅圖中能夠看到,在Http請求由IHttpHandler處理以前,它須要經過一系列的Http Module;在請求處理以後,它須要再次經過一系列的Http Module,那麼這些Http Module是如何組成的?用來作什麼呢?本文將對Http Module做以介紹。html
暫時先不考慮咱們本身實現Http Module的狀況。在.Net中,Http Module 是實現了IHttpModule接口的程序集。IHttpModule 接口自己並無什麼好大寫特寫的,由它的名字能夠看出,它不過是一個普普統統的接口而已。實際上,咱們關心的是實現了這些接口的類,若是咱們也編寫代碼實現了這個接口,那麼有什麼用途。通常來講,咱們能夠將Asp.Net中的事件分紅三個級別,最頂層是 應用程序級事件、其次是頁面級事件、最下面是控件級事件,事件的觸發分別與 應用程序週期、頁面週期、控件週期緊密相關。而 Http Module 的做用是與應用程序事件 密切相關的。web
咱們經過Http Module在Http請求管道(Pipeline)中註冊指望對應用程序事件作出反應的方法,在相應的事件觸發的時候(好比說BeginRequest事件,它在應用程序收到一個Http請求並即將對其進行處理時觸發),便會調用Http Module註冊了的方法,實際的工做在這些方法中執行。.Net 自己已經有不少的Http Module,其中包括 表單驗證Module(FormsAuthenticationModule), Session 狀態Module(SessionStateModule),輸出緩存Module (OutputCacheModule)等。編程
在註冊咱們本身編寫的 Http Module 以前,先來看看Asp.Net中已經有的HttpModule。與 Http Handler相似,咱們須要打開機器上C:\WINDOWS\Microsoft.NET\Framework\ v2.0.50727\CONFIG 目錄下的 web.config 文件。找到 <httpModules/> 結點,應該能夠看到下面的內容:api
<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>瀏覽器
咱們先從結點上看,type屬性與上一節所說的http handler結點的type屬性相似,都表明了相應的程序集。可是,與http handler 不一樣,module只提供了一個name屬性,沒有諸如 path這樣指定某一特定(或者用通配符 * 表明某一種類)文件的處理程序。這是與Module的特色相關的,咱們知道 module 是響應應用程序週期中觸發的事件,對於全部提交到aspnet_isapi.dll的請求都同樣,即使請求只是像相似http://www.tracefact.net/images/logo.gif 這樣獲取一張圖片而已(對ISAPI進行過設置之後,默認aspnet_isapi.dll不接手圖片文件)。緩存
與Http handler相似,在這冊咱們本身的http module 時,假設類名爲ModuleDemo,位於myNameSpace命名空間下,程序集名稱爲myDll,咱們只需將myDll.dll拷貝到Bin目錄下,並在站點的 web.config 文件 system.web 結點下建立 httpModules 結點:服務器
<system.web>
<httpModules>
<add name="CustomModuleName" type="myNameSpace.ModuleDemo, myDll"/>
</httpModules>
</system.web>app
type屬性由分號「,」分爲兩部分,前面是命名空間及類名,也就是類型名;後面是程序集名。若是咱們將代碼建立在App_Code目錄中,則不須要再指定程序集名。asp.net
name屬性由咱們本身命名,不必定與類名相同,此處我將它命名爲「CustomModuleName」。咱們能夠經過應用程序(HttpApplication)的Modules屬性獲取HttpModuleCollection集合,而後經過name屬性,進一步獲取HttpModule對象。ide
經過name屬性,咱們還能夠在global.asax中文件中編寫自定義HttpModule暴露出的事件的處理程序,它採用的格式是:void ModuleName_EventName(object sender, EventArgs e)。咱們將在後面作更詳細介紹。
下面這張表格列出了C:\WINDOWS\Microsoft.NET\Framework\ v2.0.50727\CONFIG下的Web.Config中的 Asp.Net 內置的Http Modules 及其主要做用。
名稱 | 類型 | 功能 |
OutputCache | System.Web.Caching.OutputCacheModule | 頁面級輸出緩存 |
Session | System.Web.SessionState.SessionStateModule | Session狀態管理 |
WindowsAuthentication | System.Web.Security.WindowsAuthenticationModule | 用集成Windows身份驗證進行客戶端驗證 |
FormsAuthentication | System.Web.Security.FormsAuthenticationModule | 用基於Cookie的窗體身份驗證進行客戶端身份驗證 |
PassportAuthentication | System.Web.Security.PassportAuthenticationModule | 用MS護照進行客戶身份驗證 |
RoleManager | System.Web.Security.RoleManagerModule | 管理當前用戶角色 |
UrlAuthorization | System.Web.Security.UrlAuthorizationModule | 判斷用戶是否被受權訪問某一URL |
FileAuthorization | System.Web.Security.FileAuthorizationModule | 判斷用戶是否被受權訪問某一資源 |
AnonymousIdentification | System.Web.Security.AnonymousIdentificationModule | 管理Asp.Net應用程序中的匿名訪問 |
Profile | System.Web.Profile.ProfileModule | 管理用戶檔案文件的創立 及相關事件 |
ErrorHandlerModule | System.Web.Mobile.ErrorHandlerModule | 捕捉異常,格式化錯誤提示字符,傳遞給客戶端程序 |
咱們將在後面用編程的方式來查看它。
看了這麼多理論知識,本節將開始動手寫點程序,實現本身的Http Module。咱們首先須要看下IHttpModule 接口,它包括下面兩個方法:
public void Init(HttpApplication context);
public void Dispose();
Init():這個方法接受一個HttpApplication對象,HttpApplication表明了當前的應用程序,咱們須要在這個方法內註冊 HttpApplication對象暴露給客戶端的事件。可見,這個方法僅僅是用來對事件進行註冊,而實際的事件處理程序,須要咱們另外寫方法。
整個過程很好理解:
NOTE:若是你不瞭解事件註冊等相關內容,請參閱 C#中的委託與事件 一文。
Dispose():它能夠在進行垃圾回收以前進行一些清理工做。
綜上所述:實現一個 IHttpModule 的模板通常是這樣的:
public class ModuleDemo:IHttpModule
{
public void Init(HttpApplication context) {
// 註冊HttpApplication應用程序 BeginRequest 事件
// 也能夠是其餘任何HttpApplication暴露出的事件
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e) {
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
// 作些實際的工做,HttpContext對象都得到了,剩下的基本能夠自由發揮了
}
public void Dispose() {
}
}
本例中,咱們僅用BeginRequest事件和 EndRequest 事件對 Http Module 的使用做以說明。咱們經過這個範例,瞭解 Http Module 基本的使用方法。
首先,請建立一個新的站點,在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 的處理,請求到達</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的處理,請求結束</h1>");
}
public void Dispose() {
}
}
上面的代碼很簡單,它註冊了 HttpApplication實例的 BeginRequest 事件 和 EndRequest事件,事件處理方法的做用僅僅是在http請求開始和結束的時候,給http請求的輸入流中分別寫入不一樣的內容。
接下來在 Web.config 的 System.web 結點中寫入如下內容:
<system.web>
<httpModules>
<add name="MyModule" type="ModuleDemo" />
</httpModules>
</system.web>
而後,打開創建站點時自動建立的 Default.aspx文件,在裏面打幾個字,爲了作區分,我輸入的是:位於.aspx頁面上的文字。而後,咱們在瀏覽器中打開它,應該會看到像這樣:
而後咱們再新建一個 Default2.aspx,在瀏覽器中瀏覽,能夠看到,兩個頁面的效果相同。這說明對於不一樣的兩個文件,http Module都起了做用,可見它確實是位於應用程序級,而非頁面級。
如今,咱們再打開站點中的一張圖片文件,發現顯示出的是一個紅叉叉,爲什呢?由於Http Module 針對是http 請求,而不是某個或某一類文件,因此當請求一張圖片的時候,咱們編寫的http Module依然會起做用,將文字插入到二進制圖片中,破壞了文件格式,天然只能顯示紅叉叉了。
NOTE:若是你發現你的圖片顯示正常,請不要驚訝,事情是這樣的:回想一下第一節咱們討論到的,對於圖片文件,由IIS直接處理,並不會交由aspnet_isapi.dll,因此,Module沒法捕獲對於圖片類型文件的請求。解決方法就是在IIS中進行設置一下。
這裏須要提請注意的是:若是你使用Vs2005自帶的Local Server,那麼你無需對IIS進行設置,全部的不論圖片仍是任何文件類型,都會交由aspnet_isapi.dll處理。
如今,咱們經過遍歷 HttpModuleCollection 集合來查看註冊給應用程序的全部 Http Module 的名稱。
新建一個文件 RegisteredModules.aspx,在代碼後置文件中添加以下方法:
private string ShowModules() {
HttpApplication app = Context.ApplicationInstance; //獲取當前上下文的HttpApplication環境
HttpModuleCollection moduleCollection = app.Modules; //獲取全部Module集合
// 獲取全部的 Module 名稱
string[] moduleNames = moduleCollection.AllKeys;
System.Text.StringBuilder results = new System.Text.StringBuilder(); //遍歷結果集
foreach (string name in moduleNames) {
// 得到Module名稱
results.Append("<b style='color:#800800'>名稱:" + name + "</b><br />");
// 得到Module類型
results.Append("類型:" + moduleCollection[name].ToString() + "<br />");
}
return results.ToString();
}
而後在Page_Load方法中輸出一下:
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(ShowModules());
}
咱們應該能夠看到下面這樣的畫面:
與以前列出的那張表格比較一下,能夠看出是幾乎徹底一致的(多了一個DefaultAuthentication)。另外注意上圖的倒數第四行,那不是咱們本身定義的Module麼?name爲MyModule,類型爲ModuleDemo。
早在asp時代,你們就知道這個文件了。它主要用於放置對於 應用程序事件或者 Session事件的響應程序。你們熟悉的有Application_Start、Application_End、Session_Start、Session_End 等。
在asp.net中,Glabal不只能夠註冊應用程序和Session事件,還能夠註冊Http Module暴露出的事件;不只能夠註冊系統Module的事件,也能夠註冊咱們本身義的Module暴露出的事件。在具體介紹以前,這裏須要首先注意兩點:
好了,咱們如今修改以前 ModuleDemo 範例程序,給它像下面這樣給它添加一個事件(爲了使程序簡潔一些,我作了簡化):
public class ModuleDemo : IHttpModule {
// 聲明一個事件
public event EventHandler ExposedEvent;
// Init方法僅用於給指望的事件註冊方法
public void Init(HttpApplication context) {
context.BeginRequest += new EventHandler(context_BeginRequest);
}
// 處理BeginRequest 事件的實際代碼
void context_BeginRequest(object sender, EventArgs e) {
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
context.Response.Write("<h3 style='color:#00f'>來自HttpModule的處理,請求到達</h3><hr>");
OnExposedEvent(new EventArgs()); // 調用方法
}
protected override void OnExposedEvent(EventArgs e) {
if (ExposedEvent != null) // 若是Global中有註冊
ExposedEvent(this, e); // 調用註冊了的方法
}
public void Dispose() {
}
}
接下來,咱們在站點中建立一個 Global.asax 文件,在裏面添加以下代碼,注意到格式是:void 模塊名_事件名(object sender, EventArgs e)。
void MyModule_ExposedEvent(object sender, EventArgs e)
{
Response.Write("<h3 style='color:#800800'>來自 Global.asax 的文字</h2>");
}
如今,咱們打開以前的頁面,應該能夠見到這樣,可見,咱們成功的將 Glabal.asax文件與咱們本身定義的Http Module所暴露出的事件 ExposedEvent 聯繫到了一塊兒:
本文簡單地介紹了什麼是Http Module。咱們首先了解了Http Module的做用,而後查看了Asp.Net 內置的Module,接着咱們介紹了IHttpModule接口,並經過了一個簡單的範例實現了此接口,最後咱們討論了 Http Module與 Global.asax 文件的聯繫。
本文僅僅是對IHttpModule做以簡單介紹,對其更多的實際應用,會在後續文章中補充。
但願這篇文章能給你帶來幫助!
本文的源代碼下載:http://www.tracefact.net/sourcecode/Introduction-to-HttpModule.rar
出處:http://www.cnblogs.com/JimmyZhang/archive/2007/11/25/971878.html