MVC之前的那点事儿系列(4):Http Pipeline详细分析(上)
文章內(nèi)容
繼續(xù)上一章節(jié)的內(nèi)容,通過HttpApplicationFactory的GetApplicationInstance靜態(tài)方法獲取實例,然后執(zhí)行該實例的BeginProcessRequest方法進行執(zhí)行余下的Http Pipeline 操作,代碼如下:
// Get application instance IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);那GetApplicationInstance這個方法究竟做了啥呢?難道只是new一個新對象出來?感覺應該不像,那我們就來看看HttpApplicationFactory類的GetApplicationInstance靜態(tài)方法源碼:
internal static IHttpHandler GetApplicationInstance(HttpContext context) { if (_customApplication != null)return _customApplication; // Check to see if it's a debug auto-attach requestif (context.Request.IsDebuggingRequest) return new HttpDebugHandler(); _theApplicationFactory.EnsureInited();_theApplicationFactory.EnsureAppStartCalled(context);return _theApplicationFactory.GetNormalApplicationInstance(context); }里面有3行代碼我已經(jīng)標記為粗體了,在解釋每行代碼的具體作用之前,先看看_theApplicationFactory對象實例從哪里來,通過查看該字段的聲明代碼可以看到它是單例的實現(xiàn)。
// the only instance of application factory private static HttpApplicationFactory _theApplicationFactory = new HttpApplicationFactory();第一行粗體代碼是執(zhí)行,該實例的EnsureInited方法,這個方法會通過lock的方式調(diào)用Init方法(好處自然不用多說了吧),代碼如下:
private void EnsureInited() {if (!_inited) {lock (this) { if (!_inited) {Init(); _inited = true; }} } }通過查找 Init方法的代碼以及其中2行如下代碼里的細節(jié),我們可以得知,這2行代碼主要是從global.asax獲取內(nèi)容,然后進行編譯。
_appFilename = GetApplicationFile(); CompileApplication();所以,HttpApplicationFactory._theApplicationFactory.EnsureInited() 的方法首先檢查HttpApplicationFactory是否被初始化,如果沒有,就通過HttpApplicationFactory.Init()進行初始化。在Init()中,先獲取global.asax文件的完整路徑,然后調(diào)用CompileApplication()對global.asax進行編譯。
第2行粗體的EnsureAppStartCalled方法,最終會調(diào)用如下的私有方法FireApplicationOnStart,代碼如下:
private void FireApplicationOnStart(HttpContext context) { if (_onStartMethod != null) { HttpApplication app = GetSpecialApplicationInstance();app.ProcessSpecialRequest(context,_onStartMethod,_onStartParamCount, this,EventArgs.Empty, null); RecycleSpecialApplicationInstance(app); } }通過代碼我們能夠得知HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context) 創(chuàng)建特定的HttpApplication實例,觸發(fā)ApplicationOnStart事件,執(zhí)行ASP.global_asax中的Application_Start(object sender, EventArgs e)方法。然后在處理完事件以后就立即被回收掉,因為系統(tǒng)初始化只需要一次,但是其中的GetSpecialApplicationInstance里會對IIS7做一些特殊的事情,我們后面的章節(jié)會講到。
第3行的粗體代碼是我們這里要說的重點,它方法里的代碼如下:
private HttpApplication GetNormalApplicationInstance(HttpContext context) {HttpApplication app = null; lock (_freeList) {if (_numFreeAppInstances > 0) {app = (HttpApplication)_freeList.Pop(); _numFreeAppInstances--;if (_numFreeAppInstances < _minFreeAppInstances) { _minFreeAppInstances = _numFreeAppInstances;} }}if (app == null) { // If ran out of instances, create a new oneapp = (HttpApplication)HttpRuntime.CreateNonPublicInstance(_theApplicationType); using (new ApplicationImpersonationContext()) {app.InitInternal(context, _state, _eventHandlerMethods); }}return app; }如果在有空閑的HttpApplication實例,就直接用,如果沒有就新創(chuàng)建,然后調(diào)用InitInternal方法進行初始化相關(guān)的內(nèi)容,最后返回該HttpApplication實例。
?
讓我們來看看HttpApplication的核心方法InitInternal里都是干了什么事兒吧,先上代碼,有點多,但是很值得:
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) { Debug.Assert(context != null, "context != null");// Remember state_state = state; PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES); try {try { // Remember context for config lookups_initContext = context;_initContext.ApplicationInstance = this;// Set config path to be application path for the application initializationcontext.ConfigurationPath = context.Request.ApplicationPathObject; // keep HttpContext.Current working while running user codeusing (new DisposableHttpContextWrapper(context)) { // Build module list from configif (HttpRuntime.UseIntegratedPipeline) {Debug.Assert(_moduleConfigInfo != null, "_moduleConfigInfo != null");Debug.Assert(_moduleConfigInfo.Count >= 0, "_moduleConfigInfo.Count >= 0"); try {context.HideRequestResponse = true; _hideRequestResponse = true; InitIntegratedModules();}finally { context.HideRequestResponse = false;_hideRequestResponse = false; } }else { InitModules();// this is used exclusively for integrated modeDebug.Assert(null == _moduleContainers, "null == _moduleContainers"); }// Hookup event handlers via reflection if (handlers != null)HookupEventHandlersForApplicationAndModules(handlers); // Initialization of the derived class_context = context;if (HttpRuntime.UseIntegratedPipeline && _context != null) { _context.HideRequestResponse = true;} _hideRequestResponse = true; try { Init();}catch (Exception e) {RecordError(e); }} if (HttpRuntime.UseIntegratedPipeline && _context != null) {_context.HideRequestResponse = false; }_hideRequestResponse = false;_context = null;_resumeStepsWaitCallback= new WaitCallback(this.ResumeStepsWaitCallback); // Construct the execution steps array if (HttpRuntime.UseIntegratedPipeline) { _stepManager = new PipelineStepManager(this);} else {_stepManager = new ApplicationStepManager(this);}_stepManager.BuildSteps(_resumeStepsWaitCallback);} finally { _initInternalCompleted = true;// Reset config pathcontext.ConfigurationPath = null;// don't hold on to the context _initContext.ApplicationInstance = null;_initContext = null; } }catch { // Protect against exception filters throw;} }該代碼主要有2個功能,一個是初始化大家熟悉的HttpModules,一個是通過BuildSteps執(zhí)行20多個生命周期事件的處理函數(shù)(這部分內(nèi)容,我們將在下一章節(jié)詳細講解Http Pipeline)。通過上面的代碼我們可以看出,每個功能都有一個特殊判斷,判斷IIS是否是IIS7的集成模式,如果是就有特殊的步驟,如果不是就走一般的步驟,兩者直接的差異分別是:IIS7初始化HttpModules的時候會從網(wǎng)站配置的Modules里讀取(因為IIS7預加載CLR和大批量Modules),BuildSteps的時候, IIS7集成模式走的是自己特殊的流程(加載服務器上的HttpModules)。
讓我們先總結(jié)一下再看代碼,InitInternal方法的主要功能如下:
至此,除了20多個周期事件和Handler相關(guān)的代碼我們沒有講解,其它和HttpApplication相關(guān)的并且對我們有幫助的,已經(jīng)差不多清晰了。關(guān)于20多個周期事件和執(zhí)行Handler方面的內(nèi)容,我們下一章節(jié)再做詳細解釋。
參考資料:
http://msdn.microsoft.com/en-us/magazine/cc188942.aspx
http://msdn.microsoft.com/en-us/library/bb470252.aspx
http://www.cnblogs.com/zhaoyang/archive/2011/11/16/2251200.html
同步與推薦
本文已同步至目錄索引:MVC之前的那點事兒系列
MVC之前的那點事兒系列文章,包括了原創(chuàng),翻譯,轉(zhuǎn)載等各類型的文章,如果對你有用,請推薦支持一把,給大叔寫作的動力。
總結(jié)
以上是生活随笔為你收集整理的MVC之前的那点事儿系列(4):Http Pipeline详细分析(上)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用C#中的string.Replace有
- 下一篇: 使用MvcContrib的FormHel