http://www.cnblogs.com/OceanEyes/archive/2012/08/13/aspnetEssential-1.html#_label0css
咱們上網時,在瀏覽器地址輸入網址:Http://www.cnblogs.com,按下回車,一張網頁就呈如今咱們眼前。這究竟發生了什麼?對於一名優秀的Programmer來講,我想有必要一下熟悉瀏覽器--->服務器請求的過程。html
ASP.NET是運行在公共語言運行時刻時(CLR)上的應用程序框架。他用來在服務器端構建功能強大的web應用程序。當瀏覽器請求 ASP.NET 文件時,IIS 會把該請求傳遞給服務器上的 ASP.NET 引擎,ASP.NET 引擎會逐行地讀取該文件,並執行文件中的腳本,最後,ASP.NET 文件會以純 HTML 的形式返回瀏覽器。程序員
客戶端瀏覽器和服務器之間的請求響應是經過Socket進行通訊,基於HTTP協議,客戶端發送一次HTTP請求,服務器接收到請求,處理以後向瀏覽器迴應響應報文。那麼什麼是HTTP協議呢?web
當瀏覽器尋找到Web服務器地址後,瀏覽器將幫助咱們把對服務器的請求轉換爲一系列參數(消息)發給Web服務器,瀏覽器和Web服務器的對話中,須要使用雙方都能理解語法規範進行通訊,這種程序之間進行通訊的語法規定,咱們稱之爲協議。瀏覽器與服務器之間的協議是應用層協議,當前遵循的協議是HTTP/1.1。HTTP/1.1協議時Web開發的基礎,這是一個無狀態協議,客戶端瀏覽器和服務器經過Socket通訊進行請求和響應完成一次會話。每次會話中,通訊雙方發送的數據稱爲消息,分爲兩種:請求消息和響應消息。編程
對於消息而言,通常他有三部分組成,而且消息的頭和消息體之間用一個空行進行分隔:api
咱們經過瀏覽器插件HttpWatch Professional能夠清晰看到瀏覽器和服務器之間的通訊內容:數組
瞭解了什麼是HTTP協議以後,咱們在回到先前提出的那個問題,瀏覽器的請求怎樣到達服務器?瀏覽器
咱們知道要訪問一個網站,必需要其部署在相應服務器軟件上(如IIS),瀏覽器向服務器發送請求以後,當請求經過Socket到達服務器時,首先服務器Windows內核中的HTTP.SYS組件捕獲請求,根據URL的請求地址將其轉發到應用程序池(Application Pool,ASP.NET應用程序必須運行在一個應用程序池中),再由運行在應用程序池裏的工做者進程(Worker Process,用於裝載專門處理ASP.NET頁面的一個ISAPI擴展程序:aspnet_isapi.dll)響應請求,當請求處理完成時,HTTP.SYS又將結果發送出去(HTTP.SYS會在內部創建一個緩存區,用於緩存近期的處理結果)。當HTTP.SYS請求分析這是一個須要交給IIS服務器處理的HTTP請求時,HTTP.SYS組件就會把此次請求交給IISl處理,服務器軟件(IIS)會判斷用戶請求的是靜態頁面(Html)仍是動態頁面(Aspx.Ashx),若是請求的是Html靜態頁面或者js,css,xml以及圖片等,IIS直接返回請求的Html靜態頁面和js等相應文件。那麼若是請求的是動態頁面呢?仍是向處理靜態頁面同樣嗎?顯然是不可能的。IIS服務器會分析請求的類型,而後從處理程序映射(即下文IIS服務器擴展)表中去匹配,當在處理程序映射表中可以匹配到請求的類型時,那麼IIS服務器就將請求交給處理程序映射表中所對應的程序來處理。當IIS發現,在處理程序映射表中沒有能匹配的項的時候,就直接返回請求所對應物理路徑下的文件,如Html,JS,CSS,JPG,PNG等。緩存
因爲IIS服務器在設計時引入了開放的ISAPI接口標準,具有極高的可擴展性。在覈心組件不變的狀況下可靈活支持不一樣類型不一樣版本的ASP.NET應用程序。安全
ISAPI(Internet Server Application Programming Interface)
ISAPI(服務器應用編程接口),它爲開發人員提供了強大的可編程能力,只要按照標準接口開發不一樣類型的Web應用程序的ISAPI擴展程序,就能實現對IIS功能上的擴展,從而使IIS能夠處理不一樣類型的客戶端請求。IIS管理器提供了應用程序配置功能,能夠對不一樣的客戶端請求配置不一樣的ISAPI擴展程序ISAPI擴展程序一般以DLL形式存在,能夠被IIS加載並調用。有了基於ISAPI的擴展擴展程序,IIS服務器就能夠根據客戶端請求的資源擴展名,來決定應由哪一個ISAPI擴展程序來處理客戶端請求,而後就能夠將請求轉發給合適的ISAPI擴展程序。
實際上客戶發起的請求最終要由aspnet_isapi.dll(被工做者進程Worker Process裝載)傳遞給aspnet_wp.exe去處理,.NET平臺下稱其爲ASP.NET Process(簡稱爲WP),該文件位於.Net Framework安裝目錄下,與aspnet_isapi.dll所在位置相同。當aspnet_isapi接收到IIS轉發的ASP.NET請求後,會將請求放入隊列,並根據實際狀況分配請求處理任務給WP進程。一旦請求被轉送給WP進程,WP進程便會通知aspnet_isapi請求正在被處理。這個通知的過程是經過同步I/O完成的,這麼實現目的是爲了保證處理過程的完整性,由於只有當請求在aspnet_isapi內部被標記爲"executing"後,WP纔會真正開始處理該請求。此後請求便在WP的上下文環境中執行。當執行結束後處理結果會經過一個異步的開放管道回送給aspnet_isapi,這時請求的狀態會被更新爲「Done」。接着請求就會從隊列中清除。若是WP進程崩潰,全部正在處理中的請求都將維持「executing」狀態一段時間,等到aspnet_isapi檢測到WP進程死掉後,會自動丟棄全部的請求並釋放已經分配的資源。
WP會分析每個請求的信息解析出其中的虛擬目錄信息,並檢查該虛擬目錄對應的AppDomain(應用程序域)是否已經存在,若是不存在,則建立一個新的AppDomain(ApplicationManager建立應用程序域),而後使用它。不然直接重用已經創建的AppDomain對象。這裏的AppDomain指的是.NET中引入的應用程序域的概念,程序集管理的最小邏輯單位爲應用程序域,包括四個重要的機制,隔離、卸載、安全、配置,它能夠理解爲一個進程或一個邊界或一個容器,它是應用程序的執行環境.NET下全部的應用程序都運行在AppDomain中,每個ASP.NET應用程序IIS中的站點或者虛擬目錄都會有一個AppDomain與之對應,它保存了Applcation對象、Cache等全局變量。
當aspnet_wp.exe接受到aspnet_isapi.dll的請求後,就將請求轉給指定虛擬目錄對應的AppDomain中的ISAPIRuntime對象,ISAPIRuntime.ProcessRequest()開始進入ASP.NET,並將瀏覽器發送請求消息封裝成HttpWorkerRequest類(抽象類,開發環境中對應SimpleWorkRequest)。以後再執行HttpRuntime的靜態方法:ProcessRequestNoDemand(參數爲封裝了瀏覽器請求的信息:HttpWorkerRequest)
在Asp.Net中,準備用於處理的請求,必須封裝爲HttpWorkerRequest類型的對象,這是一個抽象類:
[ComVisibleAttribute(false)] public abstract class HttpWorkerRequest
客戶的請求首先會被ISAPIRuntme對象ProcessRequest方法處理
建立了HttpWorkerRequest 類型的wr對象,由於ISAPIWorkerRequest 繼承於HttpWorkerRequest
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)] public int ProcessRequest(IntPtr ecb, int iWRType) { IntPtr zero = IntPtr.Zero; if (iWRType == 2) { zero = ecb; ecb = UnsafeNativeMethods.GetEcb(zero); } ISAPIWorkerRequest wr = null; try { bool useOOP = iWRType == 1; wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP); wr.Initialize(); ...... if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal)) { HttpRuntime.ProcessRequestNoDemand(wr); return 0; } HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString("Hosting_Phys_Path_Changed", new object[] { appDomainAppPathInternal, appPathTranslated })); return 1; } ...... } |
HttpRuntime調用ProcessRequestNoDemand方法:
internal static void ProcessRequestNoDemand(HttpWorkerRequest wr) { RequestQueue queue = _theRuntime._requestQueue; wr.UpdateInitialCounters(); if (queue != null) { wr = queue.GetRequestToExecute(wr); } if (wr != null) { CalculateWaitTimeAndUpdatePerfCounter(wr); wr.ResetStartTime(); ProcessRequestNow(wr); } }該方法先從請求隊列中取出一個請求,而後更新請求的引用計數器的信息,而後ProcessRequestNow方法處理請求。
在這兒終於找到了HttpRuntime這個對象了:
internal static void ProcessRequestNow(HttpWorkerRequest wr) { _theRuntime.ProcessRequestInternal(wr); } |
_theRuntime就是HttpRuntime類型的對象,他在HttpRuntime的靜態構造函數初始化。 static HttpRuntime() { ...... _theRuntime = new HttpRuntime(); _theRuntime.Init(); AddAppDomainTraceMessage("HttpRuntime::cctor*"); } |
點擊進入ProcessRequsetNow(Wr)方法,Wr即封裝了HTTP Message的HttpWorkRequest對象
在HttpRuntime接受到請求後,馬上經過HttpWorkerRequest傳遞的參數進行分析和分解,建立方便用戶網站應用程序處理用的對象。HttpRequest,HttpResponse
終於發現了HttpContext,根據HttpWorkerRequest初始化HttpContext
private void ProcessRequestInternal(HttpWorkerRequest wr) { ...... else { HttpContext context; try { context = new HttpContext(wr, false); } catch { try { wr.SendStatus(400, "Bad Request"); wr.SendKnownResponseHeader(12, "text/html; charset=utf-8"); byte[] data = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>"); wr.SendResponseFromMemory(data, data.Length); wr.FlushResponse(true); wr.EndOfRequest(); return; } finally { Interlocked.Decrement(ref this._activeRequestCount); } } wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, context); HostingEnvironment.IncrementBusyCount(); try { try { this.EnsureFirstRequestInit(context); } catch { if (!context.Request.IsDebuggingRequest) { throw; } } ...... } } |
在進入看看:根據WR,初始化了請求參數的類型HttpRequest對象和處理迴應類型HttpReponse對象
internal HttpContext(HttpWorkerRequest wr, bool initResponseWriter) { this._timeoutStartTimeUtcTicks = -1; this._timeoutTicks = -1; this._threadAbortOnTimeout = true; this.ThreadContextId = new object(); this._wr = wr; this.Init(new HttpRequest(wr, this), new HttpResponse(wr, this)); if (initResponseWriter) { this._response.InitResponseWriter(); } PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_EXECUTING); } |
privatevoid ProcessRequestInternal(HttpWorkerRequest wr) ProcessRequestInternal這個方法很重要,前面分析了它建立了上下文對象HttpContext,接下來分析HttpApplication的建立。
{ ..... IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context); ......
try
{
this.EnsureFirstRequestInit(context);
}
......
context.Response.InitResponseWriter();
......if (applicationInstance is IHttpAsyncHandler) { IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance; context.AsyncAppHandler = handler2; handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context); } ...... } } }
- EnsureFirstRequestInit()方法完成第一次請求初始化工做,該方法鎖定全局變量_beforeRequestFirst,而後調用FirstRequestInit(context)完成配置文件的加載,初始化請求隊列,裝載Bin目錄下全部程序集工做,而後更新_beforeRequestFirst=false;context.FirstRequest=true;
private void EnsureFirstRequestInit(HttpContext context) { if (this._beforeFirstRequest) { lock (this) { if (this._beforeFirstRequest) { this._firstRequestStartTime = DateTime.UtcNow; this.FirstRequestInit(context); this._beforeFirstRequest = false; context.FirstRequest = true; } } } }
- 執行InitResponseWrite建立HttpWrite對象,用於寫入結果返回信息。
- 建立HttpApplication實例,HttpApplicationFactory.GetApplicationInstance(注意其實不是這個方法直接建立,而是經過這個方法裏面又調用了GetNormalApplicationInstance方法來建立默認的HttpApplication實例)
- 那什麼是HttpApplicationFactotry?
- HttpApplicationFactotry用於負責管理一個HttpApplication的對象池。
看一下HttpApplication這個類的申明:
[ToolboxItem(false)]
public class HttpApplication : IComponent, IDisposable, IHttpAsyncHandler, IHttpHandler, IRequestCompletedNotifier, ISyncContext
{}
調用HttpApplicationFactory對象的GetNormalApplicationInstance獲得一個HttpApplication實例:
internal static IHttpHandler GetApplicationInstance(HttpContext context) { ......return _theApplicationFactory.GetNormalApplicationInstance(context); }
GetApplicationInstance方法生成一個默認的HttpApplication對象,HttpApplication實現了IHttpAsyncHandler接口。
調用HttpApplication對象(實現了IHttpAsyncHandler接口)的BeginProcessRequest方法執行客戶請求。
if (applicationInstance is IHttpAsyncHandler)
{
IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
context.AsyncAppHandler = handler2;
handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);
}
OK,回到前一步,再深刻一步,進入GetNormalApplicationInstance方法以後,咱們看到了HttpApplication對象是如何被建立和初始化:
private HttpApplication GetNormalApplicationInstance(HttpContext context) { HttpApplication state = null; ...... if (state == null) { state = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType); using (new ApplicationImpersonationContext()) { state.InitInternal(context, this._state, this._eventHandlerMethods); } } ...... }
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers)咱們發現HttpApplication類提供了一個名爲InitInternal的方法,調用它來完成HttpApplication實例的初始化工做,點擊進入InitInternal方法內部:
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) { this._state = state; PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES); ...... this.InitModules(); Label_006B: if (handlers != null) { this.HookupEventHandlersForApplicationAndModules(handlers); } ...... ..... if (HttpRuntime.UseIntegratedPipeline) { this._stepManager = new PipelineStepManager(this); } else { this._stepManager = new ApplicationStepManager(this); } this._stepManager.BuildSteps(this._resumeStepsWaitCallback); } ...... }
首先初始化Modules(InitModules)
private void InitModules() { HttpModuleCollection modules = RuntimeConfig.GetAppConfig().HttpModules.CreateModules(); HttpModuleCollection other = this.CreateDynamicModules(); modules.AppendCollection(other); this._moduleCollection = modules; this.InitModulesCommon(); } 接下來完成事件的綁定(19個管道事件):BuildSteps: |
if (HttpRuntime.UseIntegratedPipeline) { this._stepManager = new PipelineStepManager(this); } else { this._stepManager = new ApplicationStepManager(this); } this._stepManager.BuildSteps(this._resumeStepsWaitCallback); } ...... BuildSteps完成HttpApplication19個管道事件的註冊: 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)); } 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));//----------------------> 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(newHttpApplication.CallHandlerExecutionStep(app));//---------------------->用於建立處理用戶請求的對象(Handler)
|
在HttpApplication對象初始化時,首先會調用InitModules方法來加載在web.config文件中配置的全部HttpModule模塊。
接着HookupEventHandlersForApplicationAndModules方法被調用,這個方法完成global.asax文件中配置的HttpModule或HttpApplication事件的綁定
最後ApplicationStopManager對象的BuildSteps方法被調用,完成HttpApplication19個管道事件的註冊。這個方法很重要,它將建立各類HttpApplication.IExecutionStep保存到一個數組列表:
internal override void BuildSteps(WaitCallback stepCallback) { ..... this._execSteps = new HttpApplication.IExecutionStep[steps.Count]; steps.CopyTo(this._execSteps); ..... }
以便在BeginProcessRequest方法內部調用ResumeSteps方法依次執行這些對象的Execute()方法,完成各類處置。
調用BeginProcessRequest方法來實現IHttpAsyncHandler接口中定義的方法處理請求:IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { this._context = context; this._context.ApplicationInstance = this; this._stepManager.InitRequest(); this._context.Root(); HttpAsyncResult result = new HttpAsyncResult(cb, extraData); this.AsyncResult = result; if (this._context.TraceIsEnabled) { HttpRuntime.Profile.StartRequest(this._context); } this.ResumeSteps(null);//---------->依次執行管道事件 return result; }
|
BeginProcessRequest執行過程
|
void HttpApplication.IExecutionStep.Execute() { HttpContext context = this._application.Context; HttpRequest request = context.Request; if (EtwTrace.IsTraceEnabled(5, 1)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_ENTER, context.WorkerRequest); } context.Handler = this._application.MapHttpHandler(context, request.RequestType, request.FilePathObject, request.PhysicalPathInternal, false); if (EtwTrace.IsTraceEnabled(5, 1)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_LEAVE, context.WorkerRequest); } }
這兒調用了一個很重要的方法MapHttpHandler:
context.Handler = this._application.MapHttpHandler(context, request.RequestType, request.FilePathObject, request.PhysicalPathInternal, false);
internal IHttpHandler MapHttpHandler(HttpContext context, string requestType, VirtualPath path, string pathTranslated, bool useAppConfig) { IHttpHandler handler = (context.ServerExecuteDepth == 0) ? context.RemapHandlerInstance : null; ... IHttpHandlerFactory factory = this.GetFactory(mapping); try { IHttpHandlerFactory2 factory2 = factory as IHttpHandlerFactory2; if (factory2 != null) { handler = factory2.GetHandler(context, requestType, path, pathTranslated); } else { handler = factory.GetHandler(context, requestType, path.VirtualPathString, pathTranslated); } } ... .... } return handler; }
經過實現了IHttpHandlerFactory(PageHandlerFactory 或者 SimpleHandlerFactory等)建立了HttpHandler
由於steps.Add(new HttpApplication.MapHandlerExecutionStep(app))註冊了Handler,因此會在第八個事件裏經過反射建立了頁面請求的對象(實現了IHttpHandler接口)。void HttpApplication.IExecutionStep.Execute() { HttpContext context = this._application.Context; IHttpHandler handler = context.Handler; ..... ... IHttpAsyncHandler handler2 = (IHttpAsyncHandler) handler; this._sync = false; this._handler = handler2; .... }而後再第11個和12個事件之間,會調用了第八個事件建立的頁面對象的ProcessRequest方法,具體內容詳看我下一篇文章:《ASP.NET那點鮮爲人知的事(二)》
在Asp.Net中,Asp.Net服務器對於每一次請求的處理過程是相同的,都要通過HttpApplication處理管道,管道內部的處理過程是固定的,在服務器處理請求的各個階段,伴隨着處理的進行,一次觸發對應的事件,以便程序員在處理的各個階段完成自定義的處理工做。
首先觸發的事件是BeginRequest,這個事件標誌着ASP.NET服務器處理工做的開始,也是程序員在ASP.NET中針對請求可以處理的第一個事件。
開始處理請求後,第一個重要的工做就是肯定請求用戶的身份以及實現安全機制。這個工做經過AuthenticateRequest和PostAuthenticateRequest兩個事件提供檢查當前請求用戶身份的機會。PostAuthenticateRequest則表示用戶身份已經檢查完成,檢查後的用戶能夠經過HttpContext的User屬性獲取列。
public IPrincipal User { get { return this._principalContainer.Principal; } [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries"), SecurityPermission(SecurityAction.Demand, ControlPrincipal=true)] set { this.SetPrincipalNoDemand(value); } } |
Iprincipal又有一個名爲Identity,類型了System.Security.Principal.IIdentity屬性
|
當ASP.NET獲取用戶身份後,根據當前請求的用戶身份,開始請求權限的檢查工做。當第四個事件AuthorizeRequest觸發的時候開始進行用戶的權限檢查,而第五個事件PostAuthorizeRequest則標誌已經完成用戶權限檢查工做。若是用戶沒有經過安檢,通常狀況下將跳過剩餘事件,直接觸發EndRequest事件結束處理請求過程。
當用戶獲取了請求權限,那麼服務器開始準備用最快的方式來使用戶獲得迴應結果。ResolveRequestCache事件標誌着到從前緩存的結果進行檢查,看看是否能夠直接從之前的緩存結果中直接獲取處理結果,PostResolveRequestCache表示緩存檢查結束。
當不能從緩存中獲取結果時,必須經過一次處理來計算出當前請求的結果。在ASP.NET中,用戶處理請求以獲得結果的對象稱爲處理程序Handler。爲了處理這個這個請求,ASP.NET必須按照匹配規則找到一個處理當前請求的處理程序,PostMapRequestHandler事件表示當前ASP.NET已經獲取了這個處理程序,HttpContext的Handler屬性就表示這個處理程序對象。
獲得了處理程序以後,還不能立刻開始進行處理,這是因爲處理請求還須要與這個請求有關的數據,好比說這個用戶上一次向服務器發送請求的時候,在服務器上報錯了一些這個用戶特有的數據。因爲HTTP協議的無狀態性,狀態管理問題是個核心問題,因此ASP時代就引入Session,提供基於會話狀態的管理。爲了獲取這個用戶在之前保存的數據,經過AcquireRequestState事件取得請求狀態,PostAcquireRequest事件則表示已經完成了用戶數據的獲取工做,能夠再處理中使用了。
PreRequestHandlerExcute事件用來通知程序員,處理程序就要開始進行處理工做了,若是用戶的狀態已經獲取以後,還有須要的處理程序之進行的工做,那麼就在這個事件中處理吧。在PreRequestHandlerExcute事件以後,ASP.NET服務器將經過執行處理程序完成請求處理工做。這個處理程序有多是一個WebForm,也多是Web服務。這個工做是在第11個事件和第12個事件之間完成的。
處理程序以後,服務器開始進行掃尾工做,PostRequestHandlerExcute事件通知程序員,ASP.NET服務器處理程序已經完成。
在處理完成以後,因爲處理程中,用戶可能修改了用於特定的專屬數據,那麼修改以後的用戶狀態數據須要進行序列化或者進行保存處理。ReleaseRequestState事件通知程序員須要釋放這些狀態數據,PostReleaseRequestState則表示已經釋放完成。
在處理完成以後,若是須要將此次處理結果緩存起來,以便於後繼的請求能夠直接使用這個結果,UpdateRequestCache事件提供了處理的機會,PostUpdateRequestCache則表示緩存已經更新完畢。
在ASP.NET4.0中,新增長了兩個事件完成處理的日誌工做:LogRequest表示將此次請求加入日誌,PostLogRequest表示完成了日誌工做。
在前面的事件中,請求並不必定要通過全部的事件,好比說,用戶沒用通過受權的檢查,那麼將跳事後面的事件,可是,EndRequest事件是全部請求都要通過的最後一個HttpApplication處理管道的事件,也是程序員處理的ASP.NET處理請求中的最後一個機會。這個事件以後,處理的結果將被迴應到瀏覽器,完成ASP.NET服務器的處理工做。