翔如菲菲

其实天很蓝,阴云总会散;其实海不宽,此岸连彼岸.

导航

ASP.NET Http Runtime Pipeline I

相信大家都使用过ASP.NET进行过基于Web的应用开发,ASP.NET是什么?如果站在一个相对High Level的角度,我们可以这样来定义ASP.NET:ASP.NET是一个基于Web的开发平台,提供构建企业级应用所需的Service、Programming Model和Software的Infrastructure。如果我们以一个Low Level的角度来看,它本质上就是一个消息处理器:他接受IIS(确切地说应该是ASP.NET ISAPI)Forward的Http Request (我们可以看成是一个Request Message),经过一系列的处理,最终产生一个用户希望的Response(这也是一个Message,对于.aspx Page来说是一个Html document,对于一个Web Service来说是一个Soap)。所以本篇文章的主要目的在于站在一个相对Low Level的角度介绍ASP.NET的整个Http Request Processing Model。我们访问一个基于ASP.NET的资源,IIS是第一道屏障,在第一个部分我分别就IIS 5.x和IIS 6的差异介绍了IIS对Http Request的处理,今天我们来继续后面的故事。

一.从Unmanaged EnvironmentManaged Environment

IIS收到一个基于ASP.NET资源文件的访问,它会把Http Request交给一个ASP.NET ISAPI Extension处理。ASP.NET ISAPI 会加载CLR,从而创建一个托管的环境。ASP.NET ISAPI Extension定义在一个名为aspnet_isapi.dll中,aspnet_isapi.dll是一个纯Native的、高效的Dll,也就是说,虽然ASP.NET ISAPI通过加载CLR创建一个托管的环境,但是ASP.NET ISAPI本省却运行在一个Unmanaged的环境中。而我们的ASP.NET Application确是完全的Managed code,运行在一个Managed的环境中。要了解ASP.NET Http Runtime Pipeline这个纯托管的Runtime,我们必须先了解从Unmanaged Environment到Managed Environment的这道桥梁。



上图简单表述了在IIS 6环境下,从非托管环境到托管环境的过程。从图中我们可以看到,ASP.NET ISAPI运行在一个非托管环境之中。ASP.NET ISAPI经过一系列COM级别的class调用,最终的调用降临到一个托管的、继承自System.Web.Hosting.ISAPIRuntime类的对象上。ISAPIRuntime 是一个特殊的class,他实现了Interface System.Web.Hosting.IISAPIRuntime。下面是该Interface的定义。通过定义我们可以看到,这是一个基于COM的Interface,也就是说Caller可以通过COM的方式调用实现该Interface的Class的对象。在这里,这个最初的Caller就是ASP.NET ISAPI。从这里我们可以总结出:ASP.NET ISAPI通过调用System.Web.Hosting.ISAPIRuntime Instance的ProcessRequest方法,进而从非托管的环境进入了托管的环境

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

通过System.Web.Hosting.IISAPIRuntime Interface中的ProcessRequest方法的签名,我们可以看出该方法包含两个参数,其中一个是名为ecb的Unmanaged Pointer,另一个是useProcessModel。ECB全称是Execution Control Block,在整个Http Request Processing过程中起着非常重要的作用,我们现在来简单介绍一个ECB。

ISAPI顾名思义,就是实现了一些基于Internet Server的API。Aspnet_isapi.dll实现了这些API,对于IIS来说,它可以调用这些API进入托管的环境实现对ISAPIRuntime的调用,对于ISAPIRuntime来说,它需要调用ASP.NET ISAPI实现一些必要的功能,比如获得Server Variable的数据,获得通过Post Mehod传回Server的数据;以及最终将Response的内容返回给ASP.NET ISAPI,并通过ASP.NET ISAPI返回到Client。一般地ISAPIRuntime不能直接调用ASP.NET ISAPI,而是通过一个对象指针实现对其的调用,这个对象就是ECB,ECB实现了对ISAPI的访问。

还有一点特别需要强调的是,ISAPI对ISAPIRutime的调用是异步的,也就是说ISAPI调用ISAPIRutime之后立即返回。这主要是出于Performance和Responsibility考虑的,因为ASP.NET Application天生就是一个多线程的应用,为了具有更好的响应能力,异步操作是最有效的解决方式。但是这里就会有一个问题,我们知道我们对ASP.NET 资源的调用本质上是一个Request/Response的Message Exchange Pattern,异步调用往往意味着ISAPI将Request传递给ISAPIRuntime,将不能得到ISAPIRuntime最终生成的Response,这显然是不能接受的。而ECB解决了这个问题,ISAPI在调用ISAPIRutime的ProcessRequest方法时会将自己对应的ECB的指针传给它,ISAPIRutime不但可以将最终生成的Response返回给ISAPI,还能通过ECB调用ISAPI获得一些所需的数据

明白ECB是怎么回事之后,我们通过Reflector简单了解一下ISAPIRutime的ProcessRequest的实现:

public sealed class ISAPIRuntime : MarshalByRefObject, IISAPIRuntime, IRegisteredObject
{

    private static int _isThisAppDomainRemovedFromUnmanagedTable;
    
private const int WORKER_REQUEST_TYPE_IN_PROC = 0;
    
private const int WORKER_REQUEST_TYPE_IN_PROC_VERSION_2 = 2;
    
private const int WORKER_REQUEST_TYPE_OOP = 1;
    [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Minimal), SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
    
public ISAPIRuntime()
    {
        HostingEnvironment.RegisterObject(
this);
    }
    
public void DoGCCollect()
    {
        
for (int i = 10; i > 0; i--)
        {
            GC.Collect();
        }
    }
    
public int ProcessRequest(IntPtr ecb, int iWRType)
    {
        IntPtr zero = IntPtr.Zero;
        
if (iWRType == 2)
        {
            zero = ecb;
            ecb = UnsafeNativeMethods.GetEcb(zero);
        }

//签名:internal abstract class ISAPIWorkerRequest : HttpWorkerRequest

        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)
        {

……
        }
    }
    
public void StartProcessing()
    {
    }
    
public void StopProcessing()
    {
        HostingEnvironment.UnregisterObject(
this);
    }
}

上面的代码完成下面两个任务:

通过传入的ECB和iWRType创建一个叫做ISAPIWorkerRequest的对象
wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);

然后调用HttpRuntime.ProcessRequestNoDemand(wr),通过将创建的ISAPIWorkerRequest的对象作为参数传入。

HttpRuntime.ProcessRequestNoDemand的调用真正进入了ASP.NET Runtime Pipeline,这是一个相对复杂的过程。在这里我想简单说说ISAPIWorkerRequest这个重要class,ISAPIWorkerRequest是一个Abstract class,它已通过ECB创建基于当前Request的Context的信息,针对不同的IIS版本,具有不同的ISAPIWorkerRequest subclass,比如:ISAPIWorkerRequestOutOfProc(IIS 5.x), ISAPIWorkerRequestInProcForIIS6, ISAPIWorkerRequestInProcForIIS7。ProcessRequest。通过ISAPI传入的iWRType来创建不同HttpWorkerRequest,从而屏蔽了不同IIS的差异

二、ASP.NET Runtime Pipeline

现在我们真正进入ASP.NET管辖的范畴,下图基本上囊括整个处理过程涉及的对象,接下来我们一起来讨论这一系列的对象如

何相互协作去处理Http Request,并最终生成我们所需的Http Response。


 HttpContext

上面我们介绍了ISAPI在调用ISAPIRuntime的时候将对应的ISAPI ECB Pointer作为参数传递给了ProcessRequest方法,这个ECB pointer可以看成是托管环境和非托管环境进行数据交换的唯一通道,Server Variable和Request Parameter通过它传入ASP.NET作为进一步处理的依据,ASP.NET最后生成的Response通过它传递给ISAPI,并进一步传递给IIS最终返回到Client端。借助这个传进来的ECB Pointer,我们创建了一个ISAPIWorkerRequestISAPIWorkerRequest作为参数传入HttpRuntime.ProcessRequestNoDemand的调用。HttpRuntime.ProcessRequestNoDemand最终体现在调用ProcessRequestInternal方法上。下面是HttpRuntime的ProcessRequestNoDemand方法的实现:

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

正如他的名字体现的,HttpContext体现当前Request的上下文信息,它的生命周期直到整个Request处理结束或者处理超时。通过HttpContext对象我们可以访问属于当前Request的一系列常用的对象:Server,Session,Cache,Application,Request,Response,Trace,User,Profile等等。此外我们可以认为将一些数据放在Items属性中作为状态管理的一种方式,不过这种状态管理和其他一些常用的方式,比如Session,Cache,Application,Cookie等,具有根本性的不同之处是其生命周期仅仅维持在当前Request的Context中。

 

HttpApplicationFactory

HttpApplicationFactory内部最多可以维护20个Free HttpApplication实例,如果POOL中没有FREE的HttpApplication则创建一个新的HttpApplication,HttpApplicationFactory的代码如下:

internal class HttpApplicationFactory
{
    ......
    
private static IHttpHandler _customApplication;
    
private Stack _freeList = new Stack();
    
private const int _maxFreeSpecialAppInstances = 20;
    
private int _minFreeAppInstances;
    
private int _numFreeAppInstances;
    
private HttpApplicationState _state;
    
private static HttpApplicationFactory _theApplicationFactory = new HttpApplicationFactory();
    
internal const string applicationFileName = "global.asax";
    
internal static string GetApplicationFile()
    {
        
return Path.Combine(HttpRuntime.AppDomainAppPathInternal, "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);
    }

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

    
private void Init()
    {
        
if (_customApplication == null)
        {
            
try
            {
                
try
                {
                    
this._appFilename = GetApplicationFile();
                    
this.CompileApplication();
                }
                
finally
                {
                    
this.SetupChangesMonitor();
                }
            }
            
catch
            {
                
throw;
            }
        }
    }

    
internal static void SetCustomApplication(IHttpHandler customApplication)
    {
        
if (HttpRuntime.AppDomainAppIdInternal == null)
        {
            _customApplication = customApplication;
        }
    }
    ......

                        HttpApplication
public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable
{
   ......
   IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, 
object extraData);
   
void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result);
   
void IHttpHandler.ProcessRequest(HttpContext context);

internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers); 

   private void InitIntegratedModules()

   private void InitModules();

   private void InitModulesCommon();

   ......

   就像其名称体现的一样,HttpApplication基本上可以看成是整个ASP.NET Application的体现。HttpApplication和置于虚拟根目录的Gloabal.asax对应。通过HttpApplicationFactory.GetApplicationInstance创建一个基于Gloabal.asax的HttpApplication对象。在HttpApplicationFactory.GetApplicationInstance方法返回创建的HttpApplication对象之前,会调用一个名为InitInternal的内部方法,该方法会做一系列的初始化的操作,在这些初始化操作中,最典型的一个初始化方法为InitModules(),该方法的主要的目的就是查看Config中注册的所有HttpModule,并根据配置信息加载相应的Assembly,通过Reflection创建对应的HttpModule,并将这些Module加到HttpApplication 的_moduleCollection Filed

HttpApplication在初始化的时候会初始化所有的Modules:

public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable
{
    ......
    
private static List<ModuleConfigurationInfo> _moduleConfigInfo;

    
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers)
    {
        
this._state = state;
        PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES);
        
try
        {
            
try
            {
                
this._initContext = context;
                
this._initContext.ApplicationInstance = this;
                context.ConfigurationPath = context.Request.ApplicationPathObject;
                
using (new DisposableHttpContextWrapper(context))
                {
                    
if (HttpRuntime.UseIntegratedPipeline)
                    {
                        
try
                        {
                            context.HideRequestResponse = 
true;
                            
this._hideRequestResponse = true;
                            
this.InitIntegratedModules();
                            
goto Label_006B;
                        }
                        
finally
                        {
                            context.HideRequestResponse = 
false;
                            
this._hideRequestResponse = false;
                        }
                    }
                    
this.InitModules();
                Label_006B:
                    
if (handlers != null)
                    {
                        
this.HookupEventHandlersForApplicationAndModules(handlers);
                    }
                    
this._context = context;
                    
if (HttpRuntime.UseIntegratedPipeline && (this._context != null))
                    {
                        
this._context.HideRequestResponse = true;
                    }
                    
this._hideRequestResponse = true;
                    
try
                    {
                        
this.Init();
                    }
                    
catch (Exception exception)
                    {
                        
this.RecordError(exception);
                    }
                }
                
if (HttpRuntime.UseIntegratedPipeline && (this._context != null))
                {
                    
this._context.HideRequestResponse = false;
                }
                
this._hideRequestResponse = false;
                
this._context = null;
                
this._resumeStepsWaitCallback = new WaitCallback(this.ResumeStepsWaitCallback);
                
if (HttpRuntime.UseIntegratedPipeline)
                {
                    
this._stepManager = new PipelineStepManager(this);
                }
                
else
                {
                    
this._stepManager = new ApplicationStepManager(this);
                }
           
     this._stepManager.BuildSteps(this._resumeStepsWaitCallback);
            }
            
finally
            {
                
this._initInternalCompleted = true;
                context.ConfigurationPath = 
null;
                
this._initContext.ApplicationInstance = null;
                
this._initContext = null;
            }
        }
        
catch
        {
            
throw;
        }
    }
    
private void InitIntegratedModules()
    {
        
this._moduleCollection = this.BuildIntegratedModuleCollection(_moduleConfigInfo);
        
this.InitModulesCommon();
    }
    
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);//Module初始化
        }
        
this._currentModuleCollectionKey = null;
        
this.InitAppLevelCulture();
    }
    
private HttpModuleCollection BuildIntegratedModuleCollection(List<ModuleConfigurationInfo> moduleList)
    {
        HttpModuleCollection modules = 
new HttpModuleCollection();
        
foreach (ModuleConfigurationInfo info in moduleList)
        {
            ModulesEntry entry = 
new ModulesEntry(info.Name, info.Type, "type"null);
            modules.AddModule(entry.ModuleName, entry.Create());

        }
        
return modules;
    }
    ......
}

internal class RuntimeConfig

{

    ......

    private static RuntimeConfig s_clientRuntimeConfig;

    internal static RuntimeConfig GetAppConfig()

    {

        if (!HttpConfigurationSystem.UseHttpConfigurationSystem)

        {

            return GetClientRuntimeConfig();

        }

        return CachedPathData.GetApplicationPathData().RuntimeConfig;

    }

    private static RuntimeConfig GetClientRuntimeConfig()

    {

        if (s_clientRuntimeConfig == null)

        {

            s_clientRuntimeConfig = new ClientRuntimeConfig();

        }

        return s_clientRuntimeConfig;

    }

    internal HttpModulesSection HttpModules

    {

        get

        {

            return (HttpModulesSection) this.GetSection("system.web/httpModules", typeof(HttpModulesSection), ResultsIndex.HttpModules);

        }

}

 internal UrlMappingsSection UrlMappings
    {
        get
        {
            return (UrlMappingsSection) this.GetSection("system.web/urlMappings", typeof(UrlMappingsSection), ResultsIndex.UrlMappings);
        }
    }

    ......

}

 #endregion

HttpApplication本身并不包含对Request的任何处理,他的工作方式是通过在不同阶段出发不同Event来调用我们注册的Event Hander。

下面列出了HttpApplication所有的Event,并按照触发的时间先后顺序排列:

internal class ApplicationStepManager : HttpApplication.StepManager
{
    ......
    
private HttpApplication.IExecutionStep[] _execSteps;
    
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(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());
        this._execSteps = new HttpApplication.IExecutionStep[steps.Count];
        steps.CopyTo(
this._execSteps);
        
this._resumeStepsWaitCallback = stepCallback;
    }
    ......
}

HttpApplication ProcessRequest 如下:

HttpApplicationFactory的BeginProcessRequest异步处理请求,然后内部调用StepManager的ResumeSteps方法执行HttpApplication的IExecutionStep管道集合类来处理请求。
internal class HttpApplicationy
{
    ......
    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;
    }
    
private void ResumeSteps(Exception error)
    {
        
this._stepManager.ResumeSteps(error);
    }
    
internal Exception ExecuteStep(IExecutionStep step, ref bool completedSynchronously)
    {
        Exception exception = 
null;
        
try
        {
            
try
            {
                
if (step.IsCancellable)
                {
                    
this._context.BeginCancellablePeriod();
                    
try
                    {
                        step.Execute();
                    }
                    
finally
                    {
                        
this._context.EndCancellablePeriod();
                    }
                    
this._context.WaitForExceptionIfCancelled();
                }
                
else
                {
                    step.Execute();
                }
                
if (!step.CompletedSynchronously)
                {
                    completedSynchronously = 
false;
                    
return null;
                }
            }
            
catch (Exception exception2)
            { 
//异常处理略 }
        
catch (ThreadAbortException exception3)
        { 
//异常处理略 }
    
internal class ApplicationStepManager : HttpApplication.StepManager
    {
        
private HttpApplication.IExecutionStep[] _execSteps;
        
internal override void ResumeSteps(Exception error)
        {
            
bool flag = false;
            
bool completedSynchronously = true;
            HttpApplication application = 
base._application;
            HttpContext context = application.Context;
            HttpApplication.ThreadContext context2 = 
null;
            AspNetSynchronizationContext syncContext = context.SyncContext;
            
lock (base._application)
            {
                
try
                {
                    
try
                    {
                    Label_0045:

                       ……

                        if (syncContext.PendingOperationsCount > 0)
                        {
                            syncContext.SetLastCompletionWorkItem(
this._resumeStepsWaitCallback);
                        }
                        
else
                        {
                            
if (this._currentStepIndex >= this._execSteps.Length)
                            {
                                flag = 
true;
                            }
                            
else
                            {
                                
this._numStepCalls++;
                                context.SyncContext.Enable();
                                error = application.ExecuteStep(
this._execSteps[this._currentStepIndex], ref completedSynchronously);
                                
if (completedSynchronously)
                                {
                                    
this._numSyncStepCalls++;
                                    
goto Label_0045;
                                }
                            }
                        }
                    }
                    
finally
                    {}
                }
                
catch
                {
                    
throw;
                }
            }
            
if (flag)
            {
                context.Unroot();
                application.AsyncResult.Complete(
this._numStepCalls == this._numSyncStepCalls, nullnull);
                application.ReleaseAppInstance();
            }
        }
    }

/* CallHandlerExecutionStep :为请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步 BeginProcessRequest)处理请求*/
    
internal class CallHandlerExecutionStep : HttpApplication.IExecutionStep
    {
        
private void OnAsyncHandlerCompletion(IAsyncResult ar)
        {
            
if (!ar.CompletedSynchronously)
            {
                HttpContext context = 
this._application.Context;
                Exception error = 
null;
                
try
                {
                    
try
                    {
                        
this._handler.EndProcessRequest(ar);
                    }
                    
finally
                    {
                        context.Response.GenerateResponseHeadersForHandler();
                    }
                }
                
catch (Exception exception2)
                { 
//异常处理略 }
                
this._handler = null;
                context.SetStartTime();
                
if (HttpRuntime.IsLegacyCas)
                {
                    
this.ResumeStepsWithAssert(error);
                }
                
else
                {
                    
this.ResumeSteps(error);
                }
            }
        }

        
void HttpApplication.IExecutionStep.Execute()
        {
            HttpContext context = 
this._application.Context;
            IHttpHandler handler = context.Handler;

            
if ((handler != null) && HttpRuntime.UseIntegratedPipeline)
            {
                IIS7WorkerRequest workerRequest = context.WorkerRequest as IIS7WorkerRequest;
            }
            
if (handler == null)
            {
                
this._sync = true;
            }
            
else if (handler is IHttpAsyncHandler)
            {
                IHttpAsyncHandler handler2 = (IHttpAsyncHandler)handler;
                
this._sync = false;
                
this._handler = handler2;
                
IAsyncResult result = handler2.BeginProcessRequest(context, this._completionCallback, null);
                if (result.CompletedSynchronously)
                {
                    
this._sync = true;
                    
this._handler = null;
                    
try
                    {
                        
handler2.EndProcessRequest(result);
                    }
                    
finally
                    {
                        
context.Response.GenerateResponseHeadersForHandler();
                    }
                }
            }
            
else
            {
                
this._sync = true;
                context.SyncContext.SetSyncCaller();
                
try
                {
                  
  handler.ProcessRequest(context);
                }
                
finally
                {
                    context.SyncContext.ResetSyncCaller();
                    
if (EtwTrace.IsTraceEnabled(44))
                    {
                        EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_LEAVE, context.WorkerRequest);
                    }
                   
 context.Response.GenerateResponseHeadersForHandler();
                }
            }
        }
    }

/*MapHandlerExecutionStep :根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理。如果该请求针对从 Page 类派生的对象(页),并且需要对该页进行编译,则 ASP.NET 会在创建该页的实例之前对其进行编译。(除了配置文件中的,还有上下文中的HttpHnadler)*/
internal class MapHandlerExecutionStep : HttpApplication.IExecutionStep
    {
        
void HttpApplication.IExecutionStep.Execute()
        {
            HttpContext context = 
this._application.Context;
            HttpRequest request = context.Request;
         
   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;

        using (new ApplicationImpersonationContext())

        {

            if (handler != null)

            {

                return handler;

            }

            HttpHandlerAction mapping = this.GetHandlerMapping(context, requestType, path, useAppConfig);

            if (mapping == null)

            {

                PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_NOT_FOUND);

                PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_FAILED);

                throw new HttpException(SR.GetString("Http_handler_not_found_for_request_type", new object[] { requestType }));

            }

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

                }

            }

            //Catch 省略

             

            if (this._handlerRecycleList == null)

            {

                this._handlerRecycleList = new ArrayList();

            }

            this._handlerRecycleList.Add(new HandlerWithFactory(handler, factory));

        }

        return handler;

    } 

    //以下ExecutionStep 见源码

internalclass AsyncEventExecutionStep : HttpApplication.IExecutionStep { }
    
internalclass MaterializeHandlerExecutionStep : HttpApplication.IExecutionStep { }
    
internalclass NoopExecutionStep : HttpApplication.IExecutionStep { }
    
internalclass SendResponseExecutionStep : HttpApplication.IExecutionStep { }
    
internalclass SyncEventExecutionStep : HttpApplication.IExecutionStep { }
    
internalclass UrlMappingsExecutionStep : HttpApplication.IExecutionStep { }
    
internalclass ValidatePathExecutionStep : HttpApplication.IExecutionStep { }
    
internalclass ValidateRequestExecutionStep : HttpApplication.IExecutionStep { }
    ......
}

如上代码所示,整个的调用过程如下:,ISAPIRuntime 调用至HttpRuntime , HttpRuntime  通过HttpApplicationFactory 获取HttpApplication,HttpApplication在生成的同时加载了所有的HttpMoudule,并且通过StepManager完成对管线事件绑定及HttpHandler的加载。然后HttpRuntime 触发HttpApplication 的BeginProcessRequest开始了真正的HttpRequest请求的处理过程。

HttpApplication按照管线StepManager事先设定好的事件触发顺序,当被HttpModule订阅的事件发生,HttpModule根据请求的信息加载对应的HttpHandler到上下文中,并把控制权还给管线。HttpApplication继续按照管线进行,将所有的HttpHandler加载进来。之后过程中通过HttpModule确定使用哪个HttpHandler处理请求,直到管线调用这个 HttpHandler的ProcessRequest,这个时候HttpHandler才开始着手处理上下文中的请求,比如查找请求的具体页面地址,调用请求的方法,绘制视图等等。HttpHandler 处理完后,HttpApplication管线又将上下文的控制交还给HttpModule,HttpModule对请求最后处理后,又把控制权还给管线继续处理下面的事件,直到HttpRuntime 结束请求返回客户端

ASP.NET Application, AppDomain and HttpApplication

对于一个ASP.NET Application来说,一个Application和一个虚拟目录相对应,那么是不是一个Application 对应着一个AppDomain呢?一个Application是否就唯一对应一个Httpapplication对象呢?答案是否定的。

我们首先来看看Application和HttpApplication的关系,虽然我们对一个Application的Request最终都由一个HttpApplication对象来承载。但不能说一个Application就唯一对应一个固定的HttpApplication对象。原因很简单,ASP.NET天生具有多线程的特性,需要通过相应不同的Client的访问,如果我们只用一个HttpApplication来处理这些并发的请求,会对Responsibility造成严重的影响,通过考虑到Performance的问题,ASP.NET对HttpApplication的使用采用Pool的机制:当Request到达,ASP.NET会先在HttpApplication Pool中查找未被使用的HttpApplication对象,如果没有,则创建之,否则从Pool直接提取。对于Request处理完成的HttpApplication对象,不会马上销毁,而是把它放回到Pool中供下一个Request使用

对于Application和AppDomain的关系,可能你会说一个Application肯定只运行在一个AppDomain之中。在一般情况下这句话无可厚非,但是这却忽略了一种特殊的场景:在当前Application正在处理Request的时候,我们把web.config以及其他一些相关文件修改了,而且这种改变是可以马上被ASP.NET检测到的,为了使我们的变动能够及时生效,对于改动后的第一个Request,ASP.NET会为期创建一个新的AppDomain,而对于原来的AppDomain,也许还在处理修改前的Request,所有原来的Appdomain会持续到将原来的Request处理结束之后,所以对于一个Application,可能出现多个AppDomain并存的现象

 

 

引用:http://artech.cnblogs.com 

 

posted on 2011-08-19 11:20  翔如飞飞  阅读(422)  评论(0编辑  收藏  举报