【永春】Asp.Net頁面執行流程分析

iDotNetSpace發表於2008-06-16
HttpModule、HttpHandle的簡單使用,我們可以利用它們在頁面請求的過程中加入自己的事件處理程式。那麼在一個aspx頁面請求時後臺到底做了什麼?當然asp.net做了很多事情,過程也比較複雜,本文主要分析一下大體的流程。總體流程如下:
請求一個頁面時首先被WWW服務截獲(inetinfo.exe程式),這個程式首先判斷頁面的字尾,然後根據IIS中的配置來決定呼叫哪個擴充套件程式,比如aspx的頁面就會呼叫c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll,aspnet_isapi.dll將請求傳送給w3wp.exe程式(我們在除錯IIS中網站時就是把VS2005附加到這個程式上的)。
接下來w3wp.exe程式就會呼叫.net類庫進行具體處理:
ISAPIRuntime--&gtHttpRuntime--&gtHttpApplicationFactory--&gtHttpApplication--&gtHttpModule--HttpHandlerFactory--&gtHttpHandler 這也是本文主要分析的地方。

下面只是列出主要流程,如果喜歡鑽研的同學可以用Reflector去檢視
一:ISAPIRuntime
       bool useOOP = iWRType == 1;
        wr 
= ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
        wr.Initialize();
        
string appPathTranslated = wr.GetAppPathTranslated();
        
string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal;
        
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;
它的主要作用是呼叫一些非託管程式碼生成HttpWorkerRequest物件,該物件包含當前請求的所有資訊,然後傳遞給HttpRuntime,這裡生成的HttpWorkerRequest物件可以直接在我們的頁面中呼叫的,通過它取得原始的請求資訊:
            IServiceProvider provider = (IServiceProvider)HttpContext.Current;
            HttpWorkerRequest wr 
= (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));

二:HttpRuntime

最主要的就是private void ProcessRequestInternal(HttpWorkerRequest wr)方法:
        context = new HttpContext(wr, false);
        
        IHttpHandler applicationInstance 
= HttpApplicationFactory.GetApplicationInstance(context);
        
  IHttpAsyncHandler handler2 
= (IHttpAsyncHandler) applicationInstance;
  context.AsyncAppHandler 
= handler2;
  handler2.BeginProcessRequest(context, 
this._handlerCompletionCallback, context);
        
1、根據HttpWorkerRequest物件生成HttpContext,HttpContext應該大家都很熟悉的,它包含request、response等屬性,在頁面中經常會用到的;
2、呼叫HttpApplicationFactory來生成IHttpHandler(這裡生成的是一個預設的HttpApplication物件,HttpApplication也是IHttpHandler介面的一個實現)
3、呼叫HttpApplication物件執行請求

三:HttpApplicationFactory
正如2.2中所提到的,這裡主要是生成一個HttpApplication物件:

 internal static string GetApplicationFile()
 
{
     
return Path.Combine(HttpRuntime.AppDomainAppPathInternal, "global.asax");
 }

首先會檢視是否存在global.asax檔案,如果有的話就用它來生成HttpApplication物件,從這裡我們可以看到global.asax的檔名是在asp.net的框架中寫死的,不能修改的。如果這個檔案不存在就使用預設的物件。
建立好HttpApplication之後對它進行初始化:
    application = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
 
using (ApplicationImpersonationContext context2 = new ApplicationImpersonationContext())
 
{
     application.InitInternal(context, 
this._state, this._eventHandlerMethods);
 }

 四、HttpApplication
這個是比較複雜也比較重要的一個物件
首先是執行初始化操作,比較重要的一步就是進行HttpModule的初始化:
        private void InitModules()
        
{
            
this._moduleCollection = RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
            
this.InitModulesCommon();
        }
它會讀取web.config中所有HttpModule的配置
在HookupEventHandlersForApplicationAndModules方法中繫結Module的事件處理程式
接著進行事件實際繫結:
 if (HttpRuntime.UseIntegratedPipeline)
 
{
     
this._stepManager = new PipelineStepManager(this);
 }

 
else
 
{
     
this._stepManager = new ApplicationStepManager(this);
 }

 
this._stepManager.BuildSteps(this._resumeStepsWaitCallback);

在ApplicationStepManager的BuildSteps方法中可以看到事件的繫結執行順序:

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(new HttpApplication.CallHandlerExecutionStep(app));

 app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);
 app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);
 app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);
 steps.Add(
new HttpApplication.CallFilterExecutionStep(app));
 app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);
 app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);
 
this._endRequestStepIndex = steps.Count;
 app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);
 steps.Add(
new HttpApplication.NoopExecutionStep());
注意上面紅色標註的MapHandlerExecutionStep(讀取所有的HttpHandler配置)、CallHandlerExecutionStep就是對Handle程式進行處理的,也就是說在web.config中配置的HttpHandler都是在這裡進行處理的,執行順序如上所示
 
然後就是呼叫2.3中的方法執行請求:
Code
在ResumeSteps中就是執行事件處理程式。 

五、HttpModule

在系統web.config中預設的配置有:
Code
基本使用方法可以參見我的上一篇文章

六、HttpHandlerFactory、HttpHandler

這兩個物件在web.config中的配置方法是相同的,預設配置有:
Code

相關文章