接上一篇, 我在 HttpModule 的Init方法中, 添加了自己的事件, 在Pipeline里, 就會把握注冊的事件給執行了. 那么Pipeline是如何執行并且按照什么順序執行的呢?
現在我們重新回到HttpApplication.InitInternal()方法中來. 注: Integrated 是集成的意思, 明白這個單詞的意思之后, 下面這幾句代碼就很好理解了.
if (HttpRuntime.UseIntegratedPipeline) { this._stepManager = new PipelineStepManager(this); //集成 } else { this._stepManager = new ApplicationStepManager(this); //經典 } this._stepManager.BuildSteps(this._resumeStepsWaitCallback);
集成模式和經典模式(或IIS6)使用的是不同的StepManager,這個類的BuildSteps方法就是為了創建有序的ExecutionStep,其中包括各種事件的事情以及其它在各時間周期之間穿插的操作,最主要的操作,大家以前就應該知道的,比如哪個周期可以判定使用哪個HttpHandler,以及在哪個周期內執行這個HttpHandler的BeginProcessRequest方法。
1. 經典模式
由于不同的StepManager處理方式不同,我們先看經典模式的處理代碼:
//HttpApplication的內部類ApplicationStepManager internal override void BuildSteps(WaitCallback stepCallback) { ArrayList steps = new ArrayList(); HttpApplication app = base._application; bool flag = false; UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings; flag = urlMappings.IsEnabled && (urlMappings.UrlMappings.Count > 0); steps.Add(new HttpApplication.ValidateRequestExecutionStep(app)); steps.Add(new HttpApplication.ValidatePathExecutionStep(app)); if (flag) { steps.Add(new HttpApplication.UrlMappingsExecutionStep(app)); //Url Mapping } app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps); app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps); app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps); app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps); app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps); app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps); app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps); app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps); steps.Add(new HttpApplication.MapHandlerExecutionStep(app)); //Handle Mapping app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps); app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps); app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps); app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps); steps.Add(app.CreateImplicitAsyncPreloadExecutionStep()); steps.Add(new HttpApplication.CallHandlerExecutionStep(app)); //execute handler app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps); app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps); app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps); steps.Add(new HttpApplication.CallFilterExecutionStep(app)); //Filtering app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps); app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps); this._endRequestStepIndex = steps.Count; app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps); steps.Add(new HttpApplication.NoopExecutionStep()); this._execSteps = new HttpApplication.IExecutionStep[steps.Count]; steps.CopyTo(this._execSteps); this._resumeStepsWaitCallback = stepCallback; }
接著來看一下上面標紅的那個方法:
private void CreateEventExecutionSteps(object eventIndex, ArrayList steps) { AsyncAppEventHandler handler = this.AsyncEvents[eventIndex]; if (handler != null) { handler.CreateExecutionSteps(this, steps); } EventHandler handler2 = (EventHandler) this.Events[eventIndex]; if (handler2 != null) { Delegate[] invocationList = handler2.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { steps.Add(new SyncEventExecutionStep(this, (EventHandler) invocationList[i])); } } }
HttpApplication.EventBeginRequest 作為一個object的參數傳入這個方法了, 并且從這個方法里面看, 它被當做了一個Key值來用. 那么他具體是個啥呢? 去HttpApplication中看一下.
private static readonly object EventBeginRequest; static HttpApplication() { _dynamicModuleRegistry = new DynamicModuleRegistry(); ...... EventBeginRequest = new object(); ...... AutoCulture = "auto"; _moduleIndexMap = new Hashtable(); }
從這里能看到, 他真的就是一個object 類型的Key.
看著上面的代碼是不是有似曾相識的感覺,很多講聲明周期的文章都會提到20多個的事件(BeginRequest, EndRequest等),我們來看看這個方法的完整功能都是做了什么,歸納總結有5點:
- 對請求的Request進行驗證,ValidateRequestExecutionStep。
- 對請求的路徑進行安全檢查,禁止非法路徑訪問(ValidatePathExecutionStep)。
- 如果設置了UrlMappings, 進行RewritePath(UrlMappingsExecutionStep)。
- 執行事件處理函數,比如將BeginRequest、AuthenticateRequest轉化成可執行ExecutionStep在正式調用時候執行。
- 在這18個事件操作處理期間,根據不同的時機加了4個特殊的ExecutionStep。
- MapHandlerExecutionStep:查找匹配的HttpHandler
- CallHandlerExecutionStep:執行HttpHandler的BeginProcessRequest
- CallFilterExecutionStep:調用Response.FilterOutput方法過濾輸出
- NoopExecutionStep:空操作,留著以后擴展用
需要注意的是所有的ExecuteionStep都保存在ApplicationStepManager實例下的私有字段_execSteps里,而HttpApplication的BeginProcessRequest方法最終會通過該實例的ResumeSteps方法來執行這些操作(就是我們所說的那些事件以及4個特殊的Steps)。
2. 集成模式
好像在記憶里, 我發布的項目都是集成模式的. 那在這里來看一下集成模式是怎么執行的.
//HttpApplication 的內部類 PipelineStepManager
internal override void BuildSteps(WaitCallback stepCallback) { HttpApplication app = base._application;
//add special steps that don't currently
//correspond to a configured handler HttpApplication.IExecutionStep step = new HttpApplication.MaterializeHandlerExecutionStep(app);
//implicit map step app.AddEventMapping("ManagedPipelineHandler", RequestNotification.MapRequestHandler, false, step);
app.AddEventMapping("ManagedPipelineHandler", RequestNotification.ExecuteRequestHandler, false,
app.CreateImplicitAsyncPreloadExecutionStep());
//implicit handler routing step HttpApplication.IExecutionStep step2 = new HttpApplication.CallHandlerExecutionStep(app); app.AddEventMapping("ManagedPipelineHandler", RequestNotification.ExecuteRequestHandler, false, step2);
HttpApplication.IExecutionStep step3 = new HttpApplication.TransitionToWebSocketsExecutionStep(app); app.AddEventMapping("ManagedPipelineHandler", RequestNotification.EndRequest, true, step3); HttpApplication.IExecutionStep step4 = new HttpApplication.CallFilterExecutionStep(app);
//normally, this executes during UpdateRequestCache as a high priority module app.AddEventMapping("AspNetFilterModule", RequestNotification.UpdateRequestCache, false, step4);
//for error conditions, this executes during LogRequest as high priority module app.AddEventMapping("AspNetFilterModule", RequestNotification.LogRequest, false, step4); this._resumeStepsWaitCallback = stepCallback; }
來看一下 RequestNotification.MapRequestHandler 是個什么東東.
[Flags] public enum RequestNotification { AcquireRequestState = 0x20, AuthenticateRequest = 2, AuthorizeRequest = 4, BeginRequest = 1, EndRequest = 0x800, ExecuteRequestHandler = 0x80, LogRequest = 0x400, MapRequestHandler = 0x10, PreExecuteRequestHandler = 0x40, ReleaseRequestState = 0x100, ResolveRequestCache = 8, SendResponse = 0x20000000, UpdateRequestCache = 0x200 }
從這里看, 他是一個枚舉, 使用的時候, 肯定也是當做一個key值來用的. 但是為什么這里的枚舉值少了許多呢?看這里的1,2,4之間, 好像少了3(PostAuthenticateRequest). 這是為啥呢?
沒辦法, 我只能直接去 HttpApplication 里面先看看這個事件.
public event EventHandler PostAuthenticateRequest { add { this.AddSyncEventHookup(EventPostAuthenticateRequest, value, RequestNotification.AuthenticateRequest, true); } remove { this.RemoveSyncEventHookup(EventPostAuthenticateRequest, value, RequestNotification.AuthenticateRequest, true); } }
在這里發現, 他使用的是 RequestNotification.AuthenticateRequest, 那 AuthenticateRequest 事件呢, 用的是什么?
public event EventHandler AuthenticateRequest { add { this.AddSyncEventHookup(EventAuthenticateRequest, value, RequestNotification.AuthenticateRequest); } remove { this.RemoveSyncEventHookup(EventAuthenticateRequest, value, RequestNotification.AuthenticateRequest); } }
他們使用的是同一個Key, 并且調用的是同一個方法 AddSyncEventHookup, 只是Post時, 多入了一個參數true
那么就看一下這個方法吧
private void AddSyncEventHookup(object key, Delegate handler, RequestNotification notification, bool isPostNotification) { this.ThrowIfEventBindingDisallowed(); this.Events.AddHandler(key, handler); if (this.IsContainerInitalizationAllowed) { PipelineModuleStepContainer moduleContainer = this.GetModuleContainer(this.CurrentModuleCollectionKey); if (moduleContainer != null) { SyncEventExecutionStep step = new SyncEventExecutionStep(this, (EventHandler) handler); moduleContainer.AddEvent(notification, isPostNotification, step); } } }
接著往下看AddEvent方法.
internal void AddEvent(RequestNotification notification, bool isPostEvent, HttpApplication.IExecutionStep step) { int index = EventToIndex(notification); List<HttpApplication.IExecutionStep>[] listArray = null; if (isPostEvent) { if (this._modulePostSteps == null) { this._modulePostSteps = new List<HttpApplication.IExecutionStep>[0x20]; } listArray = this._modulePostSteps; } else { if (this._moduleSteps == null) { this._moduleSteps = new List<HttpApplication.IExecutionStep>[0x20]; } listArray = this._moduleSteps; } List<HttpApplication.IExecutionStep> list = listArray[index]; if (list == null) { list = new List<HttpApplication.IExecutionStep>(); listArray[index] = list; } list.Add(step); }
以這種方式, 節約了許多枚舉值.
接著看 AddEventMapping 方法:
private void AddEventMapping(string moduleName, RequestNotification requestNotification, bool isPostNotification, IExecutionStep step) { this.ThrowIfEventBindingDisallowed(); if (this.IsContainerInitalizationAllowed) { PipelineModuleStepContainer moduleContainer = this.GetModuleContainer(moduleName); if (moduleContainer != null) { moduleContainer.AddEvent(requestNotification, isPostNotification, step); } } }
從這里能看到, 事件被注冊到 PipelineModuleStepContainer 類型的一個moduleContainer 容器中了.
以上代碼有2個地方和經典模式不相同:
- IIS7集成模式沒有使用MapHandlerExecutionStep來裝載ExecutionStep(也就是查找對應的HttpHandler),而是通過MaterializeHandlerExecutionStep類來獲得HttpHandler,方式不一樣,但最終都是調用HttpApplication.GetFactory方法來獲取的,只不過IIS7集成模式有一些特殊操作而已罷了。
- IIS7集成模式是通過HttpApplication的AddEventMapping方法來添加事件的,從而將事件再次加入到前面所說的ModuleContainers容器。
另外有個很有技巧的代碼:上述4個Steps所加的周期都不是準確的周期,比如CallHandlerExecutionStep應該是加載RequestNotification的枚舉值PreExecuteRequestHandler 和ExecuteRequestHandler之間,為什么呢?因為本身CallHandlerExecutionStep只是一個特殊的step而不暴露事件的,所以枚舉里也沒有,那怎么辦?回頭看看AddEventMapping方法的第一個參數,它代表的是HttpModule的名字,查看其中的代碼得知,在執行所有事件的時候,會遍歷所有HttpModuel名稱集合然后先執行全部BeginRequest事件,再全部執行AuthenticateRequest事件,以此類推,那我們能不能來偽造一個HttpModule的名稱作為參數傳遞給AddEventMapping方法呢,答案是肯定的,看上面的代碼,發現有2個偽造的名稱分別是常量字符串 "AspNetFilterModule" (HttpApplication.IMPLICIT_FILTER_MODULE)和 "ManagedPipelineHandler" (HttpApplication.IMPLICIT_HANDLER),而因為之前其它HttpModule里的各種事件都已經load完了,所以這2個偽造HttpModule的是放在集合的最后面,所以在執行ExecuteRequestHandler類別的事件的時候,最后一個事件肯定就是這個偽造HttpModule的事件,再加上偽造HttpModule里沒有別的事件,所以它對應的ExecutionStep的執行效果其實和IIS6里CallHandlerExecutionStep的效果是一樣的,就這樣,通過一個很奇特的技巧達到同樣的目的。
最后,我們來總結一下.
在IIS7經典模式下,是用 Event+事件名稱做key將所有事件的保存在HttpApplication的Events屬性對象里,然后在BuildSteps里統一按照順序組裝,中間加載4個特殊的ExecutionStep,最后在統一執行;
在IIS7集成模式下,是通過HttpModule名稱+RequestNotification枚舉值作為key將所有的事件保存在HttpApplication的ModuleContainers屬性對象里,然后也在BuildSteps里通過偽造HttpModule名稱加載那4個特殊的ExecutionStep,最后按照枚舉類型的順序,遍歷所有的HttpModule按順序來執行這些事件。讀者可以自行編寫一個自定義的HttpModuel來執行這些事件看看效果如何。
最后關于Pipeline完整的圖如下:
最后,需要注意的是:HttpApplication不是HttpRuntime所創建,HttpRuntime只是向HttpApplicationFactory提出請求,要求返回一個HttpApplication對象。 HttpApplicationFactory在接收到請求后,會先檢查是否有已經存在并空閑的對象,如果有就取出一個HttpApplication對象返回給HttpRuntime,如果沒有的話,則要創建一個HttpApplication對象給HttpRunTime。
轉載參考:
文章列表