Agenda
前言:
附上Asp.net
執行請求流程圖.
上一篇文章分享HttpApplicationFactory.GetApplicationInstance
方法返回一個HttpApplication
給HttpRuntime
來呼叫使用.
今天開始介紹HttpApplication
這個很重要的類別,它可謂是我們Asp.net
中很複雜但重要的類別
Global.cs
是繼承HttpApplication
類別,但為什麼需要繼承這個類別呢? 讓我們繼續看下去.
查看原始碼好站 Reference Source
此文的程式碼比較多我會在原始碼上邊上說明相對應編號方便大家觀看
初始化HttpApplication (InitInternal)
在GetNormalApplicationInstance
返回一個HttpApplication
物件前會呼叫初始化HttpApplication.InitInternal
方法
這個方法主要做下面幾件事情
- 初始化
HttpModule
,讀取Host config
或appconfig
註冊的HttpMoudle,並調用Init方法,使用AOP
編成方式註冊使用事件 - 提供一個
Hock
給繼承Application
物件來初始化設定使用 - 判斷要走管道模式還是經典模式
- 建置
Pipleline
流程 - 建立許多實現
IExecutionStep
接口的物件並添加到目前HttpApplication
物驗的_execSteps
集合中.從這裡我們可以看到HttpApplication
是以異步的方式處理請求
HttpModule
是在InitInternal
方法中被讀取執行.
我們可以透過
HttpContext.ApplicationInstance.Modules
,得知目前所有載入HttpModule
.
下面是InitInternal
原始碼(核心動作有寫中文註解)
1 | internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers){ |
載入所有註冊HttpModule(InitModules方法)
這個方法讀取註冊的HttpModule
並共同放在一起,在一起呼叫InitModulesCommon
方法來呼叫所有Modules的Init
方法
1 | private void InitModules() { |
_moduleCollection[i].Init(this);
其中的this
就是把HttpApplication
物件本身傳入這也是為什麼我們繼承IHttpMoudel
介面可以共同使用同一個HttpApplication
物件.
1 | public interface IHttpModule |
上面呼叫的就是void Init(HttpApplication context)
方法.
如果要取得目前所註冊
HttpModule
可透過HttpApplication.Modules
屬性
HttpModule添加Asp.net事件原理解析.
我們在HttpModule
上10多個事件作擴充在ASP.net
是如何完成呢?
首先我們來看看事件方法原始碼.
發現每個事件都會呼叫AddSyncEventHookup
方法來建立事件,此方法有幾個參數
object key
:此事件識別資訊(每個事件都有自己的Object),如BeginRequest
事件傳入EventBeginRequest
物件.Delegate handler
:使用者撰寫事件方法.RequestNotification notification
:屬於哪種分群.
1 | /// <devdoc><para>[To be supplied.]</para></devdoc> |
上面AddSyncEventHookup
傳入object key
在Httpapplication
物件在一開始就會建立下面這些靜態方法(當作每個事件Key)
1 | // event handlers |
最後把事件資訊添加到Events
集合中,已便建立管道時使用.
1 | /// <devdoc> |
透過上面機制就可以確保對於Events
取得事件時順序.
管道模式 vs 經典模式
下面兩張圖是管道模式和經典模式
經典模式
管道模式
圖片來源
除了執行流程不一樣跟一些差異外,他們最終還是為了要找到一個HttpHandler
來執行.
取得執行HttpHandler物件
如果有認真看原始碼的小夥伴,會發現HttpApplication
的ProcessRequest
目前是throw一個錯誤.
那他是怎麼找到使用HttpHandler
物件並完成請求的呢?
1 | void IHttpHandler.ProcessRequest(HttpContext context) { |
因為
HttpRunTime
是呼叫異步請求BeginProcessRequest
方法.
這邊提一下 啟動吧!Asp.Net IsapiRunTime & HttpRuntime會先判斷app
物件是否實現IHttpAsyncHandler
.
HttpApplication
有實現IHttpAsyncHandler
介面.所以優先執行異步請求.
1 | if (app is IHttpAsyncHandler) { |
小結
今天我們學到
HttpApplication
去讀取所有註冊的HttpModule
並呼叫他們的Init
方法.- 經典模式和管道模式除了執行流程不同最終目標還是找尋一個
HttpHandler
HttpRunTime
是呼叫異步請求- 了解
HttpModule
添加Asp.net事件原理解析
很多文章都會提到10多個事件(BeginRequest
, EndRequest
…..等)
下篇會介紹StepManager
如何建立管道和如何呼叫事件並找尋HttpHandler
來執行.
此文作者:Daniel Shih(石頭)
此文地址: https://isdaniel.github.io/ithelp-day5/
版權聲明:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!