事情要知道根本所在原理所在寫程序更應該知道程序的運行機制本文主要介紹 的運行內幕
HttpApplication觸發事件來通知你的程序有事發生以此來負責請求流轉這作為HttpApplicationInit()函數的一部分發生(用Reflector查看SystemWebHttpApplicationInitInternal()方法和HttpApplicationResumeSteps()方法來了解更多詳情)連續設置並啟動一系列事件包括執行所有的處理器(handler)這些事件處理器映射到globalasax中自動生成的哪些事件中同時它們也映射到所有附加的HttpModule(它們本質上是HttpApplication對外發布的額外的事件接收器(sink))
HttpModule和HttpHandler兩者都是根據nfig中對應的配置被動態載入並附加到事件處理鏈中HttpModule實際上是事件處理器附加到特殊的HttpApplication事件上然而HttpHandler是用來處理應用級請求處理的終點
HttpModule和HttpHandler兩者都是在HttpApplicationInit()函數調用的一部分中被載入並附加到調用鏈上圖顯示了不同的事件它們是何時發生的以及它們影響管道的哪一部分
圖事件在ASPNET http管道中流轉的過程HttpApplication對象的事件驅動請求在管道中流轉Http Module可以攔截這些事件並覆蓋或者擴展現有的功能
HttpContext HttpModules 和 HttpHandlers
httpApplication它本身對發送給應用程序的數據一無所知它只是一個通過事件來通訊的消息對象它觸發事件並通過HttpContext對象來向被調用函數傳遞消息實際的當前請求的狀態數據由前面提到的HttpContext對象維護它提供了所有請求專有的數據並從進入管道開始到結束一直跟隨請求圖顯示了ASPNET管道中的流程注意上下文對象(即HttpContext)這個從請求開始到結束一直都是你朋友的對象可以在一個事件處理函數中保存信息並在以後的事件處理函數中取出
一旦管道被啟動HttpApplication開始象圖六那樣一個個的觸發事件每個事件處理器被觸發如果事件被掛接這些處理器將執行它們自己的任務這個處理的主要任務是最終調用掛接到此特定請求的HttpHandler處理器(handler)是ASPNET請求的核心處理機制通常也是所有應用程序級別的代碼被執行的地方記住ASPNET頁面和Web服務框架都是作為HttpHandler實現這裡也是處理請求的的核心之處模塊(module)趨向於成為一個傳遞給處理器(handler)的上下文的預處理或後處理器ASPNET中典型的默認處理器包括預處理的認證緩存以及後處理中各種不同的編碼機制
有很多關於HttpHandler和HttpModule的可用信息所以為了保持這篇文章在一個合理的長度我將提供一個關於處理器的概要介紹
HttpModule
當請求在管道中傳遞時HttpApplicaion對象中一系列的事件被觸發我們已經看到這些事件在Globalasax中作為事件被發布這種方法是特定於應用程序的可能並不總是你想要的如果你要建立一個通用的可用被插入任何Web應用程序的HttpApplication事件鉤子你可用使用HttpModule這是可復用的不需要特定語應用程序代碼的只需要nfig中的一個條目
模塊本質上是過濾器(fliter)功能上類似於ISAPI過濾器但是它工作在ASPNET請求級別上模塊允許為每個通過HttpApplication對象的請求掛接事件這些模塊作為外部程序集中的類存貯在nfig文件中被配置在應用程序啟動時被載入通過實現特定的接口和方法模塊被掛接到HttpApplication事件鏈上多個HttpModule可用被掛接在相同的事件上事件處理的順序取決於它們在nfig中聲明的順序下面是在nfig中處理器定義
<configuration>
<systemweb>
<httpModules>
<add name= BasicAuthModule
type=HttpHandlersBasicAuthWebStore />
</httpModules>
</systemweb>
</configuration>
注意你需要指定完整的類型名和不帶dll擴展名的程序集名
模塊允許你查看每個收到的Web請求並基於被觸發的事件執行一個動作模塊在修改請求和響應數據方面做的非常優秀可用為特定的程序提供自定義認證或者為發生在ASPNET中的每個請求增加其他預處理/後處理功能許多ASPNET的功能像認證和會話(Session)引擎都是作為HttpModule來實現的
雖然HttpModule看上去很像ISAPI過濾器它們都檢查每個通過ASPNET應用的請求但是它們只檢查映射到單個特定的ASPNET應用或虛擬目錄的請求也就是只能檢查映射到ASPNET的請求這樣你可以檢查所有ASPX頁面或者其他任何映射到ASPNET的擴展名你不能檢查標准的HTM或者圖片文件除非你顯式的映射這些擴展名到ASPNET ISAPI dll上就像圖中展示的那樣一個常見的此類應用可能是使用模塊來過濾特定目錄中的JPG圖像內容並在最上層通過GDI+來繪制樣品字樣
實現一個HTTP模塊是非常簡單的:你必須實現之包含兩個函數(Init()和Dispose())的IHttpModule接口傳進來的事件參數中包含指向HTTPApplication對象的引用這給了你訪問HttpContext對象的能力在這些方法上你可以掛接到HttpApplication事件上例如如果你想掛接AuthenticateRequest事件到一個模塊上你只需像列表中展示的那樣做
列表:基礎的HTTP模塊是非常容易實現的
public class BasicAuthCustomModule : IHttpModule
{
public void Init(HttpApplication application)
{
// *** Hook up any HttpApplication events
applicationAuthenticateRequest +=
new EventHandler(thisOnAuthenticateRequest);
}
public void Dispose() { }
public void OnAuthenticateRequest(object source EventArgs eventArgs)
{
HttpApplication app = (HttpApplication) source;
HttpContext Context = HttpContextCurrent;
… do what you have to do… }
}
記住你的模塊訪問了HttpContext對象從這裡可以訪問到其他ASPNET管道中固有的對象如請求(Request)和響應(Response)這樣你還可以接收用戶輸入的信息等等但是記住有些東西可能是不能訪問的它們只有在處理鏈的後段才能被訪問
你可以在Init()方法中掛接多個事件這樣你可以在一個模塊中實現多個不同的功能然而將不同的邏輯分到單獨的類中可能會更清楚的將模塊進行模塊化(譯注:這裡的模塊化和前面的模塊沒有什麼關系)在很多情況下你實現的功能可能需要你掛接多個事件例如一個日志過濾器可能在BeginRequest事件中記錄請求開始時間然後在EndRequest事件中將請求結束寫入到日志中
注意一個HttoModule和HttpApplication事件中的重點:ResponseEnd()或HttpApplicationCompleteRequest()會在HttpApplication和Module的事件鏈中抄近道看注意ResponseEnd()來獲得更多信息
注意ResponseEnd()
當創建HttpModule或者在Globalasax中實現事件鉤子的時候當你調用ResponseEnd或 AppplicationCompleteRequest的時候要特別注意這兩個函數都結束當前請求並停止觸發在HTTP管道中後續的事件然後發生將控制返回到Web服務器中當你在處理鏈的後面有諸如記錄日志或對內容進行操作的行為時因為他們沒有被觸發有可能使你上當例如sample中logging的例子就會失敗因為如果調用ResponseEnd()的話EndRequest事件並不會被觸發
From:http://tw.wingwit.com/Article/program/net/201311/11658.html