XinL

导航

Asp.net Process Model 之二:Asp.net Runtime Pipeline

      在第一篇Asp.net Process Model 之一:IIS 和 ISAPI 中学习了用户请求如何从IIS通过ISAPI将request传送到asp.net Http Runtime中的,这节学习在asp.net runtime 内部是如何处理request的。

 一、从unmanaged environment到managed environment   

       Asp.net ISAPI extension(aspnet_isapi.dll)创建aspnet_wp进程用于运行Asp.net Application,初始化aspnet_wp时加载CLR,从而创建一个managed运行环境,但是aspnet_isapi.dll是native的。那么Asp.net ISAPI extension是如何从unmanaged environment转换到managed environment呢?

      上篇提到,在初始化CLR时创建了ISPAPIRuntime实例,该实例实现IISAPIRuntime接口。ISAPIRuntime接口定义如下:

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("08a2c56f-7c16-41c1-a8be-432917a1a2d1")]
public interface IISAPIRuntime
{
    
void StartProcessing();
    
void StopProcessing();
    [
return: MarshalAs(UnmanagedType.I4)]
    
int ProcessRequest([In] IntPtr ecb, [In, MarshalAs(UnmanagedType.I4)] int useProcessModel);
    
void DoGCCollect();
}

      从接口定义可看出,该接口是COM可见的,非托管代码可以通过COM调用方式调用实现了interface的类的实例。

      ECB(Exective Control Block)

      ProcessRequest函数有两个参数,其中一个是指针参数ecb。ecb是ISAPIRuntime类对aspnet_isapi.dll的引用,用于从aspnet_isapi.dll中提取请求信息,并将响应结果传回给aspnet_isapi.dll。

      ISAPIRuntime的ProcessRequest函数定义如下:

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();
        
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;
    }
    
catch (Exception exception)
    {
        
try
        {
            WebBaseEvent.RaiseRuntimeError(exception, 
this);
        }
        
catch
        {
        }
        
if ((wr == null|| !(wr.Ecb == IntPtr.Zero))
        {
            
throw;
        }
        
if (zero != IntPtr.Zero)
        {
            UnsafeNativeMethods.SetDoneWithSessionCalled(zero);
        }
        
if (exception is ThreadAbortException)
        {
            Thread.ResetAbort();
        }
        
return 0;
    }
}

      此函数中重要之处有两点:
            ISAPIWorlerRequest wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb,useOOP)
            HttpRuntime.ProcessRequestNoDemand(wr);

      ISAPIWorkerRequest继承自HttpWorkerRequet抽象类,此抽象类定义由 ASP.NET 托管代码用于处理请求的基本辅助方法和枚举。HttpRuntime.ProcessRequest 静态方法驱动所有 ASP.NET Web 处理执行。

      aspnet_isapi.dll就是调用了ISAPIRuntime的ProcessRequest函数,从unmanaged environment转到managed environment。该函数根据aspnet_isapl指针创建新请求ISAPIWokerRequest,并将此请求对象作为参数传递给HttpRuntime.ProcessRequestNoDemand,开始进入asp.net的请求处理流程(Asp.net Runtime Pileline)。      

 二、Asp.net Runtime Pileline

      下图显示了进入托管环境的Asp.net Runtime PipleLine后的执行情况

      数据流程图为:

  
      HttpRuntime函数内依次执行HttpRuntime下面的三个分支操作。下面分别介绍各处理流程

    启动请求处理

      HttpRuntime的ProcessRequestNoDemand静态方法启动web处理,该方法会调用一系列内部函数。其中几个重要的函数有:

internal static void ProcessRequestNoDemand(HttpWorkerRequest wr)
{
    RequestQueue queue 
= _theRuntime._requestQueue;
    
if (queue != null)
    {
        wr 
= queue.GetRequestToExecute(wr);
    }
    
if (wr != null)
    {
        CalculateWaitTimeAndUpdatePerfCounter(wr);
        wr.ResetStartTime();
        ProcessRequestNow(wr);
    }
}

       该方法从运行时的请求队列中取出一个请求后,继续执行其他操作。 

Code
internal static void ProcessRequestNow(HttpWorkerRequest wr)
{
    _theRuntime.ProcessRequestInternal(wr);
}

private void ProcessRequestInternal(HttpWorkerRequest wr)
{
    HttpContext context;
    
try
    {
        context 
= new HttpContext(wr, false);
    }
    
catch
    {
        wr.SendStatus(
400"Bad Request");
        wr.SendKnownResponseHeader(
12"text/html; charset=utf-8");
        
byte[] bytes = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
        wr.SendResponseFromMemory(bytes, bytes.Length);
        wr.FlushResponse(
true);
        wr.EndOfRequest();
        
return;
    }
    wr.SetEndOfSendNotification(
this._asyncEndOfSendCallback, context);
    Interlocked.Increment(
ref this._activeRequestCount);
    HostingEnvironment.IncrementBusyCount();
    
try
    {
        
try
        {
            
this.EnsureFirstRequestInit(context);
        }
        
catch
        {
            
if (!context.Request.IsDebuggingRequest)
            {
                
throw;
            }
        }
        context.Response.InitResponseWriter();
        IHttpHandler applicationInstance 
= HttpApplicationFactory.GetApplicationInstance(context);
        
if (applicationInstance == null)
        {
            
throw new HttpException(SR.GetString("Unable_create_app_object"));
        }
        
if (EtwTrace.IsTraceEnabled(51))
        {
            EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, applicationInstance.GetType().FullName, 
"Start");
        }
        
if (applicationInstance is IHttpAsyncHandler)
        {
            IHttpAsyncHandler handler2 
= (IHttpAsyncHandler) applicationInstance;
            context.AsyncAppHandler 
= handler2;
            handler2.BeginProcessRequest(context, 
this._handlerCompletionCallback, context);
        }
        
else
        {
            applicationInstance.ProcessRequest(context);
            
this.FinishRequest(context.WorkerRequest, context, null);
        }
    }
    
catch (Exception exception)
    {
        context.Response.InitResponseWriter();
        
this.FinishRequest(wr, context, exception);
    }
}

      这个函数中重要点:
            HttpContext context = new HttpContext(wr, false);
            IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
            以及后面的XXProcessRequest方法

      HttpContext 

      HttpContext封装有关个别 HTTP 请求的所有 HTTP 特定的信息。为继承 IHttpModule 和 IHttpHandler 接口的类提供了对当前 HTTP 请求的HttpContext对象的引用。该对象提供对请求的内部 Request、Response、Server、User等有关属性的访问。它的生命周期直到Request处理结束或处理超时。

      HttpApplication

      HttpApplication可以说是asp.net Application的体现。HttpApplication本身并不包含对Request的任何处理,它的工作方式是通过在不同阶段触发不同Event来调用我们注册的Event Hander下面列出了HttpApplication所有的Event,并按照触发的时间先后顺序排列:

  • BeginRequest
  • AuthenticateRequest & Post AuthenticateRequest
  • AuthorizeRequest & Post AuthorizeRequest
  • ResolveRequestCache & Post ResolveRequestCache
  • PostMapRequestHandler:
  • AcquireRequestState & AcquireRequestState:
  • PreRequestHandlerExecute & Post RequestHandlerExecute:
  • ReleaseRequestState & Post ReleaseRequestState
  • UpdateRequestCache & PostUpdateRequestCache
  • EndRequest:

      HttpApplicationFactory.GetApplicationInstance创建一个基于Global.asax的应用程序实例。 

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);
}

      此方法经过一系列条件判断及初始化后,进入GetNormalApplicationInstance方法: 

private HttpApplication GetNormalApplicationInstance(HttpContext context)
{
    HttpApplication application 
= null;
    
lock (this._freeList)
    {
        
if (this._numFreeAppInstances > 0)
        {
            application 
= (HttpApplication) this._freeList.Pop();
            
this._numFreeAppInstances--;
            
if (this._numFreeAppInstances < this._minFreeAppInstances)
            {
                
this._minFreeAppInstances = this._numFreeAppInstances;
            }
        }
    }
    
if (application == null)
    {
        application 
= (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
        
using (new ApplicationImpersonationContext())
        {
            application.InitInternal(context, 
this._state, this._eventHandlerMethods);
        }
    }
    
return application;
}

      从方法定义看出,并不是直接创建一个HttpApplication对象,而是从一组空闲HttpAppllication实例数组中找一个来直接用,若没有空闲对象才创建新对象。由此可见,一个Asp.net Application并不是对应一个HttpApplication实例。这是因为,Asp.net是多线程的,要响应不同client的请求,如果一个Asp.net Application对应一个HttpApplication,则会对响应性能产生极大的影响。某个HttpApplication完成响应后也不会立即释放,而是放入空间队列供后续请求适用。

      在创建新的HttpApplication时,会调用方法InitInternal,在此方法中包含一条执行语句:InitModules(),该方法的主要的目的就是查看Config中注册的所有HttpModule,并根据配置信息加载相应的Assembly,通过Reflection创建对应的HttpModule,并将这些Module加到HttpApplication 的 _moduleCollection Filed中。定义如下: 

private void InitModules()
{
    
this._moduleCollection = RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
    
this.InitModulesCommon();
}

private void InitModulesCommon()
{
    
int count = this._moduleCollection.Count;
    
for (int i = 0; i < count; i++)
    {
        
this._currentModuleCollectionKey = this._moduleCollection.GetKey(i);
        
this._moduleCollection[i].Init(this);
    }
    
this._currentModuleCollectionKey = null;
    
this.InitAppLevelCulture();
}

      从配置文件中找到所有HttpModule后,逐个调用HttpModule的Init方法,完成模块的初始化。

      到目前,我们创建了响应request的HttpApplication实例,下一步就是响应客户端请求了。处理请求的命令在HttpRuntime的ProcessRequestInternal方法中

if (applicationInstance is IHttpAsyncHandler)
        {
            IHttpAsyncHandler handler2 
= (IHttpAsyncHandler) applicationInstance;
            context.AsyncAppHandler 
= handler2;
            handler2.BeginProcessRequest(context, 
this._handlerCompletionCallback, context);
        }
        
else
        {
            applicationInstance.ProcessRequest(context);
            
this.FinishRequest(context.WorkerRequest, context, null);
        }

      前面提到,ISAPI方式异步调用ISAPIRuntime,这里的响应采用异步Handler(这句推断纯属自己瞎想,不知道是否属实)。HttpApplication的ProcessRequest方法不执行任何操作,仅仅是抛出异常throw new HttpException(SR.GetString("Sync_not_supported")),真正执行响应的是BeginProcessRequest方法: 

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;
}

     在此方法中调用HttpRuntime.Profile.StartRequest启动请求。最终执行操作落入到函数InitRequest方法

private void InitRequest()
{
    
int num2;
    DataSet ds 
= _masterRequest.Clone();
    DataRow row 
= this.NewRow(ds, "Trace_Request");
    row[
"Trace_Time_of_Request"= this._context.Timestamp.ToString("G");
    
string rawUrl = this._context.Request.RawUrl;
    
int index = rawUrl.IndexOf("?", StringComparison.Ordinal);
    
if (index != -1)
    {
        rawUrl 
= rawUrl.Substring(0, index);
    }
    row[
"Trace_Url"= rawUrl;
    row[
"Trace_Request_Type"= this._context.Request.HttpMethod;
    
try
    {
        row[
"Trace_Request_Encoding"= this._context.Request.ContentEncoding.EncodingName;
    }
    
catch
    {
    }
    
if (this.TraceMode == TraceMode.SortByCategory)
    {
        ds.Tables[
"Trace_Trace_Information"].DefaultView.Sort = "Trace_Category";
    }
    
this.AddRow(ds, "Trace_Request", row);
    
string[] allKeys = this._context.Request.Headers.AllKeys;
    
for (num2 = 0; num2 < allKeys.Length; num2++)
    {
        row 
= this.NewRow(ds, "Trace_Headers_Collection");
        row[
"Trace_Name"= allKeys[num2];
        row[
"Trace_Value"= this._context.Request.Headers[allKeys[num2]];
        
this.AddRow(ds, "Trace_Headers_Collection", row);
    }
    ArrayList list 
= this._context.Response.GenerateResponseHeaders(false);
    
int num3 = (list != null? list.Count : 0;
    
for (num2 = 0; num2 < num3; num2++)
    {
        HttpResponseHeader header 
= (HttpResponseHeader) list[num2];
        row 
= this.NewRow(ds, "Trace_Response_Headers_Collection");
        row[
"Trace_Name"= header.Name;
        row[
"Trace_Value"= header.Value;
        
this.AddRow(ds, "Trace_Response_Headers_Collection", row);
    }
    allKeys 
= this._context.Request.Form.AllKeys;
    
for (num2 = 0; num2 < allKeys.Length; num2++)
    {
        row 
= this.NewRow(ds, "Trace_Form_Collection");
        row[
"Trace_Name"= allKeys[num2];
        row[
"Trace_Value"= this._context.Request.Form[allKeys[num2]];
        
this.AddRow(ds, "Trace_Form_Collection", row);
    }
    allKeys 
= this._context.Request.QueryString.AllKeys;
    
for (num2 = 0; num2 < allKeys.Length; num2++)
    {
        row 
= this.NewRow(ds, "Trace_Querystring_Collection");
        row[
"Trace_Name"= allKeys[num2];
        row[
"Trace_Value"= this._context.Request.QueryString[allKeys[num2]];
        
this.AddRow(ds, "Trace_Querystring_Collection", row);
    }
    
if (HttpRuntime.HasAppPathDiscoveryPermission())
    {
        allKeys 
= this._context.Request.ServerVariables.AllKeys;
        
for (num2 = 0; num2 < allKeys.Length; num2++)
        {
            row 
= this.NewRow(ds, "Trace_Server_Variables");
            row[
"Trace_Name"= allKeys[num2];
            row[
"Trace_Value"= this._context.Request.ServerVariables.Get(allKeys[num2]);
            
this.AddRow(ds, "Trace_Server_Variables", row);
        }
    }
    
this._requestData = ds;
}

        完成BeginProcessRequest后,HttpRuntime结束请求,进入方法FinishRequest    

Code
private void FinishRequest(HttpWorkerRequest wr, HttpContext context, Exception e)
{
    HttpResponse response 
= context.Response;
    
if (EtwTrace.IsTraceEnabled(51))
    {
        EtwTrace.Trace(EtwTraceType.ETW_TYPE_END_HANDLER, context.WorkerRequest);
    }
    SetExecutionTimePerformanceCounter(context);
    
if (e == null)
    {
        ClientImpersonationContext context2 
= new ClientImpersonationContext(context, false);
        
try
        {
            response.FinalFlushAtTheEndOfRequestProcessing();
        }
        
catch (Exception exception)
        {
            e 
= exception;
        }
        
finally
        {
            
if (context2 != null)
            {
                ((IDisposable) context2).Dispose();
            }
        }
    }
    
if (e != null)
    {
        
if (this._appOfflineMessage != null)
        {
            
try
            {
                response.StatusCode 
= 0x194;
                response.OutputStream.Write(
this._appOfflineMessage, 0this._appOfflineMessage.Length);
                response.FinalFlushAtTheEndOfRequestProcessing();
                
goto Label_00D6;
            }
            
catch
            {
                
goto Label_00D6;
            }
        }
        
using (new HttpContextWrapper(context))
        {
            ApplicationImpersonationContext context3 
= new ApplicationImpersonationContext();
            
try
            {
                
try
                {
                    response.ReportRuntimeError(e, 
truefalse);
                }
                
catch (Exception exception2)
                {
                    response.ReportRuntimeError(exception2, 
falsefalse);
                }
                response.FinalFlushAtTheEndOfRequestProcessing();
            }
            
catch
            {
            }
            
finally
            {
                
if (context3 != null)
                {
                    ((IDisposable) context3).Dispose();
                }
            }
        }
    }
Label_00D6:
    
this._firstRequestCompleted = true;
    
if (this._hostingInitFailed)
    {
        ShutdownAppDomain(ApplicationShutdownReason.HostingEnvironment, 
"HostingInit error");
    }
    
int statusCode = response.StatusCode;
    UpdatePerfCounters(statusCode);
    context.FinishRequestForCachedPathData(statusCode);
    wr.EndOfRequest();
    HostingEnvironment.DecrementBusyCount();
    Interlocked.Decrement(
ref this._activeRequestCount);
    
if (this._requestQueue != null)
    {
        
this._requestQueue.ScheduleMoreWorkIfNeeded();
    }
}

      此方法生成HttpResponse实例作为响应结果回送给Asp.net ISAPI    

 

 参考:
      http://www.cnblogs.com/artech/archive/2007/09/13/891262.html

posted on 2009-06-24 18:35  XinL  阅读(719)  评论(0编辑  收藏  举报