學習於:http://www.cnblogs.com/fish-li/archive/2011/09/05/2168073.html
ASP.NET管道中的事件處理採用了觀察者模式,"觀察者模式定義了對象之間的一種聯絡,使得當一個對象改變狀態時,所有其它的對象都可以相應地被通知到"。在這個設計模式中,觀察者就是許多HttpModule對象,被觀察的對象就是每個"請求",它的狀態是由HttpApplication 控制,用於描述當前請求的處理階段,HttpApplication會根據一個特定的順序修改這個狀態,並在每個狀態改變後引發相應的事件。 Asp.net會為每個請求分配一個HttpApplication對象來引發這些事件,因此可以讓一大批觀察者瞭解每個請求的狀態, 每個觀察者也可以在感興趣的時候修改請求的一些資料。
MSDN【IIS 5.0 和 6.0 的ASP.NET應用程式生命週期概述】
在處理該請求時將由 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 方法(或非同步版 IHttpAsyncHandler.BeginProcessRequest)。 例如,如果該請求針對某頁,則當前的頁執行個體將處理該請求。 16. 引發 PostRequestHandlerExecute 事件。17. 引發 ReleaseRequestState 事件。18. 引發 PostReleaseRequestState 事件。19. 如果定義了 Filter 屬性,則執行響應篩選。20. 引發 UpdateRequestCache 事件。21. 引發 PostUpdateRequestCache 事件。22. 引發 EndRequest 事件。23. 引發 PreSendRequestHeaders 事件。24. 引發 PreSendRequestContent 事件。
如果是IIS7,第10個事件也就是MapRequestHandler事件,而且在EndRequest 事件前,還增加了另二個事件:LogRequest 和 PostLogRequest 事件。
只有當應用程式在 IIS 7.0 整合模式下運行,並且與 .NET Framework 3.0 或更高版本一起運行時,才會支援 MapRequestHandler、LogRequest 和 PostLogRequest 事件。
補充:從BeginRequest開始的事件,並不是每個事件都會被觸發,因為在整個處理過程中,隨時可以調用Response.End() 或者有未處理的異常發生而提前結束整個過程。在那些"知名"的事件中,也只有EndRequest事件是肯定會觸發的, (部分Module的)BeginRequest有可能也不會被觸發。
小結:
1. 每個請求都將會映射到一個HttpHandler,通常也是處理請求的主要對象。
2. HttpModule可以任意訂閱這些事件,在事件處理器中也可以參與修改請求的操作。
3. 絕大多數的的請求都在【第10步】被映射到一個HttpHandler, 然後在【第15步】中執行處理過程
HttpHandler
HttpHandler通常是處理請求的核心對象。絕大多數的的請求都在【第10步】被映射到一個HttpHandler, 然後在【第15步】中執行處理過程,因此也常把這類對象稱為處理器或者處理常式。我們熟知的Page就是一個處理器, 一個ashx檔案也是一個處理器,不過ashx顯示得更原始
通常,我們需要新的HttpHandler,建立一個ashx檔案就可以了。 但也可以建立自己的HttpHandler,或者要將一類【特殊的路徑/副檔名】交給某個處理器來處理, 那麼就需要我們在web.config中註冊那個處理器。
注意:如果是【特殊的副檔名】可能還需要在IIS中註冊,原因很簡單:IIS不將請求交給Asp.net,我們的代碼根本沒機會運行!
可以在web.config中註冊一個自訂的處理器:
<httpHandlers>
<add verb="*" path="*/Test.htm" type="WebApplication1.App_Code.HtmlHandler,WebApplication1"/>
</httpHandlers>
//當瀏覽器發起一個對Test.htm請求時,該請求會被路由到WebApplication1.App_Code下的HtmlHandler處理常式進行處理
讓HttpModule工作也需要在web.config中註冊:
<httpModules>
<add name="TestModule" type="MySimpleServiceFramework.DuplexGzipModule"/>
</httpModules>
HttpModule的載入方式
Asp.net會為每個請求分配一個HttpApplication對象【意味著將會有多個HttpApplication對象】,在每個HttpApplication對象的初始化操作中,它會載入所有在web.config中註冊的HttpModule。
Accept-Encoding
只是告訴服務端:用戶端能接受什麼樣的編碼,並不能表示某次請求體的內容是壓縮過的
看不見的效能問題
對於每個Asp.net請求,每個HttpModule都會在它們所訂閱的事件中去執行一些操作邏輯。這些操作邏輯或許對一些請求是無意義的,但仍會執行。 因此,電腦將會白白浪費一些資源去執行一些無意義的代碼。
針對這種情形,解決辦法如下:
1. 去掉不需要的HttpModule
2. 在每個HttpModule的事件處理器中,首先要確定是不是自己所需要處理的請求。對一些不相關的請求,應該立即退出。
在我們建立一個Asp.net項目時,如果不做任何修改,微軟已經為我們載入了好多HttpModule 。
protected void Page_Load(object sender, EventArgs e)
{
HttpApplication app = HttpContext.Current.ApplicationInstance;
StringBuilder sb = new StringBuilder();
foreach( string module in app.Modules.AllKeys )
sb.AppendFormat(module).Append("<br />");
Response.Write(sb.ToString());
}
//輸出結果:總共有14個HttpModule
可以在web.config將不需要的Module移除,如:
<httpModules>
<remove name="Session"/>
<remove name="RoleManager"/>
</httpModules>