上一篇講了從創建應用程式域到創建ISAPIRuntime實例的過程,本篇繼續講Asp.net處理第一次請求的必要的初始化過程。 ISAPIRuntime分析 ISAPIRuntime在System.Web.Hosting中實現,它的ProcessRequest是我們處理web請求的入口。 註意方法的 ...
上一篇講了從創建應用程式域到創建ISAPIRuntime實例的過程,本篇繼續講Asp.net處理第一次請求的必要的初始化過程。
ISAPIRuntime分析
ISAPIRuntime在System.Web.Hosting中實現,它的ProcessRequest是我們處理web請求的入口。
public int ProcessRequest(IntPtr ecb, int iWRType) { IntPtr pHttpCompletion = IntPtr.Zero; if (iWRType == WORKER_REQUEST_TYPE_IN_PROC_VERSION_2) { pHttpCompletion = ecb; ecb = UnsafeNativeMethods.GetEcb(pHttpCompletion); } ISAPIWorkerRequest wr = null; try { bool useOOP = (iWRType == WORKER_REQUEST_TYPE_OOP); wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP); wr.Initialize(); String wrPath = wr.GetAppPathTranslated(); String adPath = HttpRuntime.AppDomainAppPathInternal; if (adPath == null ||StringUtil.EqualsIgnoreCase(wrPath, adPath)) { HttpRuntime.ProcessRequestNoDemand(wr); return 0; } else { HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString(SR.Hosting_Phys_Path_Changed, adPath, wrPath)); return 1; } } catch(Exception e) { try { WebBaseEvent.RaiseRuntimeError(e, this); } catch {} if (wr != null && wr.Ecb == IntPtr.Zero) { if (pHttpCompletion != IntPtr.Zero) { UnsafeNativeMethods.SetDoneWithSessionCalled(pHttpCompletion); } if (e is ThreadAbortException) { Thread.ResetAbort(); } return 0; } throw; } }
註意方法的IntPtr類型的參數ecb, 它是一個非托管的指針,用於傳遞一些必須的數據,以及最終將Response的內容返回給非托管環境ISAPI(非同步方式),然後呈現給Client用戶。方法中調用ISAPIWorkerRequest的靜態方法CreateWorkerRequest而創建ISAPIWorkerRequest對象實例,參數分別為ecb和代表WorkerRequest類型的int參數iWRType,通過判斷ecb和type類型的具體內容,來決定創建什麼類型的WorkerRequest(上述類型的ISPAIWorkerRequest都繼承於HttpWorkerRequest),上面的代碼可以看出對不同版本的IIS進行了不同的包裝,通過其Initialize方法來初始化一些基本的信息(比如:contentType, querystring的長度,filepath等相關信息)。然後調用HttpRuntime.ProcessRequestNoDemand(wr)轉入HttpRuntime處理請求,最終體現在調用ProcessRequestInternal方法上。
HttpRuntime分析
Httpruntime在System.Web下實現,我們來看其處理請求的ProcessRequestInternal方法。
private void ProcessRequestInternal(HttpWorkerRequest wr) { Interlocked.Increment(ref _activeRequestCount); if (_disposingHttpRuntime) { try { wr.SendStatus(503, "Server Too Busy"); wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8"); byte[] body = Encoding.ASCII.GetBytes("<html><body>Server Too Busy</body></html>"); wr.SendResponseFromMemory(body, body.Length); wr.FlushResponse(true); wr.EndOfRequest(); } finally { Interlocked.Decrement(ref _activeRequestCount); } return; } HttpContext context; try { context = new HttpContext(wr, false); } catch { try { wr.SendStatus(400, "Bad Request"); wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8"); byte[] body = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>"); wr.SendResponseFromMemory(body, body.Length); wr.FlushResponse(true); wr.EndOfRequest(); return; } finally { Interlocked.Decrement(ref _activeRequestCount); } } wr.SetEndOfSendNotification(_asyncEndOfSendCallback, context); HostingEnvironment.IncrementBusyCount(); try { try { EnsureFirstRequestInit(context); } catch { if (!context.Request.IsDebuggingRequest) { throw; } } context.Response.InitResponseWriter(); IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context); if (app == null) throw new HttpException(SR.GetString(SR.Unable_create_app_object)); if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, app.GetType().FullName, "Start"); if (app is IHttpAsyncHandler) { IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)app; context.AsyncAppHandler = asyncHandler; asyncHandler.BeginProcessRequest(context, _handlerCompletionCallback, context); } else { app.ProcessRequest(context); FinishRequest(context.WorkerRequest, context, null); } } catch (Exception e) { context.Response.InitResponseWriter(); FinishRequest(wr, context, e); } }
該方法中創建了熟悉的HttpContext並同時創建了HttpRequest與HttpResponse
internal HttpContext(HttpWorkerRequest wr, bool initResponseWriter) { _wr = wr; Init(new HttpRequest(wr, this), new HttpResponse(wr, this)); if (initResponseWriter) _response.InitResponseWriter(); PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_EXECUTING); }
然後通過HttpApplicationFactory的GetApplicationInstance靜態方法,獲取我們熟悉的HttpApplication對象實例(註:HttpApplication對象是繼承IHttpAsyncHandler,而IHttpAsyncHandler又繼承於IHttpHandler),然後執行調用BeginProcessRequest方法。至此正式進入了HttpApplication對象的創建以及大家熟知的HttpApplication以後的生命周期了。
HttpApplicationFactory分析
HttpApplicationFactory在System.Web下實現。
查看HttpApplicationFactory用來創建Httpapplication的GetApplicationInstance方法。
internal static IHttpHandler GetApplicationInstance(HttpContext context) { if (_customApplication != null) return _customApplication; if (context.Request.IsDebuggingRequest) return new HttpDebugHandler(); _theApplicationFactory.EnsureInited(); _theApplicationFactory.EnsureAppStartCalled(context); return _theApplicationFactory.GetNormalApplicationInstance(context); }
該方法有三個步驟:首先是EnsureInited,會檢查是否已經初始化,如果沒有會調用Init方法先獲取global.asax文件的完整路徑,然後調用CompileApplication()對global.asax進行編譯,Init方法如下。
private void Init() { if (_customApplication != null) return; try { try { _appFilename = GetApplicationFile(); CompileApplication(); } finally { SetupChangesMonitor(); } } catch { throw; } }
然後是EnsureAppStartCalled方法如果未開始啟動會調用FireApplicationOnStart。
private void EnsureAppStartCalled(HttpContext context) { if (!_appOnStartCalled) { lock (this) { if (!_appOnStartCalled) { using (new DisposableHttpContextWrapper(context)) { WebBaseEvent.RaiseSystemEvent(this, WebEventCodes.ApplicationStart); FireApplicationOnStart(context); } _appOnStartCalled = true; } } } } private void FireApplicationOnStart(HttpContext context) { if (_onStartMethod != null) { HttpApplication app = GetSpecialApplicationInstance(); app.ProcessSpecialRequest(context, _onStartMethod, _onStartParamCount, this, EventArgs.Empty, null); RecycleSpecialApplicationInstance(app); } }
這裡創建特定的HttpApplication實例,觸發ApplicationOnStart事件(會執行global.asax中的Application_Start方法)。然後在處理完事件以後就立即被回收掉,因為系統初始化只需要一次。
最後是GetNormalApplicationInstance,如果在有空閑的HttpApplication實例,就直接用,如果沒有就新創建,然後調用InitInternal方法進行初始化相關的內容,最後返回該HttpApplication實例。
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) { app = (HttpApplication)HttpRuntime.CreateNonPublicInstance(_theApplicationType); using (new ApplicationImpersonationContext()) { app.InitInternal(context, _state, _eventHandlerMethods); } } …… return app; }
HttpApplication分析
HttpApplication在System.Web下實現,首先查看HttpApplication的InitInternal方法,該方法用於初始化。
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) { Debug.Assert(context != null, "context != null"); _state = state; PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES); try { try { _initContext = context; _initContext.ApplicationInstance = this; context.ConfigurationPath = context.Request.ApplicationPathObject; using (new DisposableHttpContextWrapper(context)) { if (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(); Debug.Assert(null == _moduleContainers, "null == _moduleContainers"); } if (handlers != null) HookupEventHandlersForApplicationAndModules(handlers); _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); if (HttpRuntime.UseIntegratedPipeline) { _stepManager = new PipelineStepManager(this); } else { _stepManager = new ApplicationStepManager(this); } _stepManager.BuildSteps(_resumeStepsWaitCallback); } finally { _initInternalCompleted = true; context.ConfigurationPath = null; _initContext.ApplicationInstance = null; _initContext = null; } } catch { throw; } }
該代碼主要有2個功能,一個是初始化大家熟悉的HttpModules,一個是通過BuildSteps執行多個生命周期事件的處理函數。通過上面的代碼我們可以看出,每個功能都有一個特殊判斷,判斷IIS是否是IIS7的集成模式,如果是就有特殊的步驟,如果不是就走一般的步驟(兩者直接的差異分別是:經典模式初始化HttpModules的時候會從網站配置的Modules里讀取,集成模式會預載入CLR和大量Modules,比如載入伺服器上設置的HttpModules;另外在BuildSteps的時候, IIS7集成模式走的是自己特殊的流程)。
總結一下,InitInternal方法的主要功能如下:
InitModules():根據Web.Config的設置,載入相應的HttpModules。
InitIntegratedModules():會載入IIS7集成模式下在伺服器上設定的HttpModuels和Web.config里system.webserver下的HttpModuels。
HookupEventHandlersForAppplicationAndModules:綁定HttpApplication實例中相應的事件處理函數(在Global.asax中定義的事件處理函數)。
創建很多實現IExecutionStep介面的類的實例並添加到當前HttpApplication實例的_execSteps中(包括HttpModules中定義的周期事件處理函數和查找匹配的HttpHandler、執行HttpHandler的方法以及過濾輸出等特殊事件),等待回調時執行。從這裡我們可以看到HttpApplication是以非同步的方式處理請求, 對請求的很多處理工作都放入了_execStep等待回調時執行。
在 HttpApplication的事件如下形式定義:
public event EventHandler BeginRequest { add { AddSyncEventHookup(EventBeginRequest, value, RequestNotification.BeginRequest); } remove { RemoveSyncEventHookup(EventBeginRequest, value, RequestNotification.BeginRequest); } }
所有的事件都是調用AddSyncEventHookup方法添加進去的,其中第一個參數是以Event+事件名稱的值。
internal void AddSyncEventHookup(object key, Delegate handler, RequestNotification notification) { AddSyncEventHookup(key, handler, notification, false); }
private void AddSyncEventHookup(object key, Delegate handler, RequestNotification notification, bool isPostNotification) { ThrowIfEventBindingDisallowed(); Events.AddHandler(key, handler); if (IsContainerInitalizationAllowed) { PipelineModuleStepContainer container = GetModuleContainer(CurrentModuleCollectionKey); if (container != null) { SyncEventExecutionStep step = new SyncEventExecutionStep(this, (EventHandler)handler); container.AddEvent(notification, isPostNotification, step); } } }
經典模式下在初始化HttpModlue的時候通過調用Events.AddHandler方法,將事件添加到Events集合里,同時這個key就是Event+事件名稱,而集成模式下這些事件是添加到另外一個地方的(通過將事件hanlder包裝成SyncEventExecutionStep類型,然後調用container.AddEvent方法將事件添加到另外一個地方),也就是說if上面的Events集合是給經典模式用的,下麵的Container里的數據是給集成模式用的,這些事件是存放在HttpApplication的ModuleContainers屬性里,這個屬性的類型是PipelineModuleStepContainer[],個數就是HttpModules的個數,也就是說每個HttpModule在HttpApplication上添加的事件都放在各自的PipelineModuleStepContainer容器里。
private PipelineModuleStepContainer[] ModuleContainers { get { if (_moduleContainers == null) { Debug.Assert(_moduleIndexMap != null && _moduleIndexMap.Count > 0, "_moduleIndexMap != null && _moduleIndexMap.Count > 0"); _moduleContainers = new PipelineModuleStepContainer[_moduleIndexMap.Count]; for (int i = 0; i < _moduleContainers.Length; i++) { _moduleContainers[i] = new PipelineModuleStepContainer(); } } return _moduleContainers; } }
StepManager分析
集成模式和經典模式(或IIS6)使用的是不同的StepManager,這個類的BuildSteps方法就是為了創建有序的ExecutionStep,其中包括各種事件的事情以及其它在各時間周期之間穿插的操作,最主要的操作,大家以前就應該知道的,比如哪個周期可以判定使用哪個HttpHandler,以及在哪個周期內執行這個HttpHandler的BeginProcessRequest方法。StepManager的具體實現類(ApplicationStepManager、PipelineStepManager)和HttpApplication類在同一個文件中定義。
ApplicationStepManager的BuildSteps方法(用於經典模式)
internal override void BuildSteps(WaitCallback stepCallback ) { ArrayList steps = new ArrayList(); HttpApplication app = _application; bool urlMappingsEnabled = false; UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings; urlMappingsEnabled = urlMappings.IsEnabled && ( urlMappings.UrlMappings.Count > 0 ); steps.Add(new ValidateRequestExecutionStep(app)); steps.Add(new ValidatePathExecutionStep(app)); if (urlMappingsEnabled) steps.Add(new UrlMappingsExecutionStep(app)); // url mappings 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 MapHandlerExecutionStep(app)); // map handler 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 CallHandlerExecutionStep(app)); // execute handler app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps); app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps); app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps); steps.Add(new CallFilterExecutionStep(app)); // filtering app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps); app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps); _endRequestStepIndex = steps.Count; app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps); steps.Add(new NoopExecutionStep()); // the last is always there _execSteps = new IExecutionStep[steps.Count]; steps.CopyTo(_execSteps); _resumeStepsWaitCallback = stepCallback; } private void CreateEventExecutionSteps(Object eventIndex, ArrayList steps) { AsyncAppEventHandler asyncHandler = AsyncEvents[eventIndex]; if (asyncHandler != null) { asyncHandler.CreateExecutionSteps(this, steps); } EventHandler handler = (EventHandler)Events[eventIndex]; if (handler != null) { Delegate[] handlers = handler.GetInvocationList(); for (int i = 0; i < handlers.Length; i++) { steps.Add(new SyncEventExecutionStep(this, (EventHandler)handlers[i])); } } }
這個方法的完整功能歸納總結有以下幾點:
對請求的Request進行驗證,ValidateRequestExecutionStep。
對請求的路徑進行安全檢查,禁止非法路徑訪問(ValidatePathExecutionStep)。
如果設置了UrlMappings, 進行RewritePath(UrlMappingsExecutionStep)。
執行事件處理函數,比如將BeginRequest、AuthenticateRequest轉化成可執行ExecutionStep在正式調用時候執行。
在這多個個事件操作處理期間,根據不同的時機加了4個特殊的ExecutionStep。
MapHandlerExecutionStep:查找匹配的HttpHandler
CallHandlerExecutionStep:執行HttpHandler的BeginProcessRequest
CallFilterExecutionStep:調用Response.FilterOutput方法過濾輸出
NoopExecutionStep:空操作,留著以後擴展用
所有的ExecuteionStep都保存在ApplicationStepManager實例下的私有欄位_execSteps里,而HttpApplication的BeginProcessRequest方法最終會通過該實例的ResumeSteps方法來執行這些操作。
PipelineStepManager的BuildSteps(用於集成模式)
internal override void BuildSteps(WaitCallback stepCallback) { Debug.Trace("PipelineRuntime", "BuildSteps"); HttpApplication app = _application; IExecutionStep materializeStep = new MaterializeHandlerExecutionStep(app); app.AddEventMapping(ttpApplication.IMPLICIT_HANDLER, RequestNotification.MapRequestHandler, false, materializeStep); app.AddEventMapping(HttpApplication.IMPLICIT_HANDLER, RequestNotification.ExecuteRequestHandler, false, app.CreateImplicitAsyncPreloadExecutionStep()); IExecutionStep handlerStep = new CallHandlerExecutionStep(app); app.AddEventMapping(HttpApplication.IMPLICIT_HANDLER, RequestNotification.ExecuteRequestHandler, false, handlerStep); IExecutionStep webSocketsStep = new TransitionToWebSocketsExecutionStep(app); app.AddEventMapping(HttpApplication.IMPLICIT_HANDLER, RequestNotification.EndRequest, true, webSocketsStep); IExecutionStep filterStep = new CallFilterExecutionStep(app); app.AddEventMapping(HttpApplication.IMPLICIT_FILTER_MODULE, RequestNotification.UpdateRequestCache, false, filterStep); app.AddEventMapping(HttpApplication.IMPLICIT_FILTER_MODULE, RequestNotification.LogRequest, false, filterStep); _resumeStepsWaitCallback = stepCallback; } private void AddEventMapping(string moduleName,RequestNotification requestNotification, bool isPostNotification,IExecutionStep step) { ...... PipelineModuleStepContainer container = GetModuleContainer(moduleName); container.AddEvent(requestNotification, isPostNotification, step); }
以上代碼有2個地方和經典模式不相同:
集成模式沒有使用MapHandlerExecutionStep來裝載ExecutionStep(也就是查找對應的HttpHandler),而是通過MaterializeHandlerExecutionStep類來獲得HttpHandler,方式不一樣。
集成模式是通過HttpApplication的AddEventMapping方法來添加事件的,從而將事件加入到前面所說的ModuleContainers容器。
總結一下,在經典模式下,是用 Event+事件名稱做key將所有事件的保存在HttpApplication的Events屬性對象里,然後在BuildSteps里統一按照順序組裝,中間載入4個特殊的ExecutionStep,最後在統一執行;在集成模式下,是通過HttpModule名稱+RequestNotification枚舉值作為key將所有的事件保存在HttpApplication的ModuleContainers屬性對象里,然後也在BuildSteps里通過偽造HttpModule名稱載入那4個特殊的ExecutionStep,最後按照枚舉類型的順序,遍歷所有的HttpModule按順序來執行這些事件,可以自行編寫一個自定義的HttpModuel來執行這些事件看看效果如何。
下麵是總結一下處理第一次請求的大體處理流程。