您的位置:首页 > 编程语言 > ASP

asp.net 运行原理

2009-09-14 13:41 429 查看
主要类:
  System.Web.HttpRuntime
  System.Web.HttpApplicationFactory
  System.Web.HttpApplication
  System.Web.Compilation.BuildManager
  System.Web.Compilation.ApplicationBuildProvider
  System.Web.Compilation.BuildProvidersCompiler
  System.Web.UI.PageHandlerFactory
请求处理简要流程图:



分析:

当我们通过浏览器向ASP.NET 2.0网站的一个asp.net页面发起请求时,在服务器端首先是IIS收到请求,IIS一看是asp.net页面,心里很开心,因为这个请求不用它处理,交给ASP.NET ISAPI就行了。ASP.NET ISAPI的工作也比较轻松,他的主要任务就是安排aspnet_wp.exe处理请求,并监视aspnet_wp.exe进程的执行情况,如果aspnet_wp.exe进程太累了,不能出色地完成任务,ASP.NET ISAPI就要让他下岗,换一个新的aspnet_wp.exe来处理工作。

 aspnet_wp.exe的主要任务是将请求交给一系列称为的 HTTP 管道的托管对象。如果把ASP.NET ISAPI比做销售经理,那aspnet_wp.exe就是生产经理,而HTTP 管道就是生产的流水线。负责流水线的小组就是HttpRuntime,生产经理aspnet_wp.exe会将订单(HTTP请求)交给HttpRuntime小组的工作人员ProcessRequest(HttpWorkerRequest wr),HttpRuntime根据内部的分工,最终由ProcessRequestInternal(HttpWorkerRequest wr)在流水线上进行生产,所以ProcessRequestInternal(HttpWorkerRequest wr)是我们分析的重点。

首先看一下ProcessRequestInternal(HttpWorkerRequest wr)的代码:

private void ProcessRequestInternal(HttpWorkerRequest wr)
{
    // 初始化HttpContext实例
    HttpContext extraData = new HttpContext(wr, false);
    wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, extraData);
    Interlocked.Increment(ref this._activeRequestCount);
    HostingEnvironment.IncrementBusyCount();
    // 对第一次请求初始化
    try
    {
        try
        {
            this.EnsureFirstRequestInit(extraData);
        }
        catch
        {
            if (!extraData.Request.IsDebuggingRequest)
            {
                throw;
            }
        }
        // 初始化HttpWriter实例
        extraData.Response.InitResponseWriter();
        // 创建HttpApplication实例
        IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(extraData);
        if (applicationInstance == null)
        {
            throw new HttpException(SR.GetString("Unable_create_app_object"));
        }
        if (EtwTrace.IsTraceEnabled(5, 1))
        {
            EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, extraData.WorkerRequest, applicationInstance.GetType().FullName, "Start");
        }
        if (applicationInstance is IHttpAsyncHandler)
        {
            IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
            extraData.AsyncAppHandler = handler2;
            handler2.BeginProcessRequest(extraData, this._handlerCompletionCallback, extraData);
        }
        else
        {
            applicationInstance.ProcessRequest(extraData);
            this.FinishRequest(extraData.WorkerRequest, extraData, null);
        }
    }
    catch (Exception exception)
    {
        extraData.Response.InitResponseWriter();
        this.FinishRequest(wr, extraData, exception);
    }
}


 在HttpApplicationFactory.GetApplicationInstance中有三个关键方法:
HttpApplicationFactory._theApplicationFactory.EnsureInited();
HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context);
HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);

1) HttpApplicationFactory._theApplicationFactory.EnsureInited();
  该方法检查HttpApplicationFactory是否被初始化,如果没有,就通过HttpApplicationFactory.Init()进行初始化。
在Init()中,先获取global.asax文件的完整路径,然后调用CompileApplication()对global.asax进行编译。
那编译是如何进行的呢?
  编译的工作由BuildManager完成的。BuildManager先得到GlobalAsaxType(也就是HttpApplication),然后调用BuildManager.GetGlobalAsaxBuildResult()=》GetGlobalAsaxBuildResultInternal()=》EnsureTopLevelFilesCompiled()进行编译。
  在EnsureTopLevelFilesCompiled中,先进行CompilationStage.TopLevelFiles编译,对下面三个目录中的文件进行编译:
a. CompileResourcesDirectory();
  编译App_GlobalResources目录。
  b. CompileWebRefDirectory();
  编译App_WebReferences目录。
  c. CompileCodeDirectories();
  编译App_Code目录。

  接着进行CompilationStage.GlobalAsax 编译,对global.asax进行编译,方法调用情况:CompileGlobalAsax()=》ApplicationBuildProvider.GetGlobalAsaxBuildResult(BuildManager.IsPrecompiledApp)。
  在GetGlobalAsaxBuildResult中具体的编译是由ApplicationBuildProvider与BuildProvidersCompiler共同完成的。
  BuildProvidersCompiler.PerformBuild();进行编译工作。
  ApplicationBuildProvider.GetBuildResult得到编译的结果。
  编译成功后,会在C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Temporary ASP.NET Files/相应的目录中生成类似App_global.asax.mlgx7n2v.dll的dll文件。
  编译生成的类名为ASP.global_asax,继承自HttpApplication。
  注:如果Web目录中没有Global.asax文件,就不会编译生成App_global.asax.mlgx7n2v.dll这样的文件。

  2) HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context);
  创建特定的HttpApplication实例,触发ApplicationOnStart事件,执行ASP.global_asax中的Application_Start(object sender, EventArgs e)方法。这里创建的HttpApplication实例在处理完事件后,就被回收。

  3) HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);
  该方法创建HttpApplication实例并进行初始化(调用System.Web.HttpApplication. InitInternal()方法)。
创建HttpApplication实例是根据实际的_theApplicationType进行创建。如果Web目录中没有global.asa文件,也就是说没有动态编译生成ASP.global_asax类型,那就直接实例化HttpApplication。如果创建了ASP.global_asax类型,那就对ASP.global_asa进行实例化。
  创建HttpApplication实例之后就是调用实例的InitInternal方法。
  InitInternal方法也是我们重点分析的方法,该方法的主要功能如下:

internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers)
{
    this._state = state;
    PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES);
    this._initContext = context;
    this._initContext.ApplicationInstance = this;
    bool flag = false;
    UrlMappingsSection urlMappings = RuntimeConfig.GetAppConfig().UrlMappings;
    flag = urlMappings.IsEnabled && (urlMappings.UrlMappings.Count > 0);
    try
    {
        try
        {
            context.ConfigurationPath = context.Request.ApplicationPathObject;
            using (new HttpContextWrapper(context))
            {
                // 根据Web.Config的设置,创建相应的HttpModules。
                this.InitModules();
                // 根据发生的事件,调用HttpApplication实例中相应的事件处理函数。
                if (handlers != null)
                {
                    this.HookupEventHandlersForAppplicationAndModules(handlers);
                }
                this._context = context;
                this._hideRequestResponse = true;
                try
                {
                    this.Init();
                }
                catch (Exception exception)
                {
                    this.RecordError(exception);
                }
            }
            this._hideRequestResponse = false;
            this._context = null;
            /* 创建很多实现IExecutionStep接口的类的实例并添加到当前HttpApplication实例的_execSteps中,
             * 等待回调时执行。从这里我们可以看到HttpApplication是以异步的方式处理请求,
             * 对请求的很多处理工作都放入了_execStep等待回调时执行。
             */
            ArrayList steps = new ArrayList();
            // 对请求的路径进行安全检查,禁止非法路径访问
            steps.Add(new ValidatePathExecutionStep(this));
            // 如果设置了UrlMappings, 进行RewritePath(UrlMappingsExecutionStep)。
            if (flag)
            {
                steps.Add(new UrlMappingsExecutionStep(this));
            }
            // 执行事件处理函数,比如:BeginRequest、AuthenticateRequest等等。
            this.CreateEventExecutionSteps(EventBeginRequest, steps);
            this.CreateEventExecutionSteps(EventAuthenticateRequest, steps);
            this.CreateEventExecutionSteps(EventDefaultAuthentication, steps);
            this.CreateEventExecutionSteps(EventPostAuthenticateRequest, steps);
            this.CreateEventExecutionSteps(EventAuthorizeRequest, steps);
            this.CreateEventExecutionSteps(EventPostAuthorizeRequest, steps);
            this.CreateEventExecutionSteps(EventResolveRequestCache, steps);
            this.CreateEventExecutionSteps(EventPostResolveRequestCache, steps);
            steps.Add(new MapHandlerExecutionStep(this));
            this.CreateEventExecutionSteps(EventPostMapRequestHandler, steps);
            this.CreateEventExecutionSteps(EventAcquireRequestState, steps);
            this.CreateEventExecutionSteps(EventPostAcquireRequestState, steps);
            this.CreateEventExecutionSteps(EventPreRequestHandlerExecute, steps);
            steps.Add(new CallHandlerExecutionStep(this));
            this.CreateEventExecutionSteps(EventPostRequestHandlerExecute, steps);
            this.CreateEventExecutionSteps(EventReleaseRequestState, steps);
            this.CreateEventExecutionSteps(EventPostReleaseRequestState, steps);
            steps.Add(new CallFilterExecutionStep(this));
            this.CreateEventExecutionSteps(EventUpdateRequestCache, steps);
            this.CreateEventExecutionSteps(EventPostUpdateRequestCache, steps);
            this._endRequestStepIndex = steps.Count;
            this.CreateEventExecutionSteps(EventEndRequest, steps);
            steps.Add(new NoopExecutionStep());
            this._execSteps = new IExecutionStep[steps.Count];
            steps.CopyTo(this._execSteps);
            this._resumeStepsWaitCallback = new WaitCallback(this.ResumeStepsWaitCallback);
            /* 获取处理当前请求的HttpHandler,ASP.NET页面的运行时编译也是在这里进行的。(MapHandlerExecutionStep)
             *该处理是通过调用System.Web.HttpApplication. MapHttpHandler方法。
           *在MapHttpHandler中,首先根据访问的地址从web.config获取相应的实现IHttpHandlerFactory的类型。对于asp.net页面,
             *默认是PageHanlderFactory。然后创建PageHanlderFactory实例,调用GetHandlerHelper,
             *在GetHandlerHelper中调用BuildManager.CreateInstanceFromVirtualPath编译并创建当前请求的ASP.NET页面的实例(如果已经编译过,直接从缓存中加载)。
             *CreateInstanceFromVirtualPath经过几次方法调用,
             * 将编译任务给了BuildManager. CompileWebFile()。CompileWebFile从web.config得到相应的BuildProvider,对于.aspx文件,
             * 相应的BuildProvider是PageBuildProvider。PageBuildProvider是如何进行页面编译的,这里就不再就进一步分析了,如果你感兴趣,可以进一步研究ASP.NET 2.0的源代码。
           *5) 调用相应HttpHandler的.ProcessRequest方法处理请求(如果是异步方式,调用BeginProcessReques)。(CallHandlerExecutionStep)
           *6) 将响应内容写入Filter。(CallFilterExecutionStep)
           *5. 调用HttpApplication实例的BeginProcessRequest异步处理请求。
             * 上面所讲的_execSteps中所发生的许多事情,都是在HttpRuntime调用HttpApplication BeginProcessRequest之后,在BeginProcessRequest中调用ResumeSteps后执行的。
             */
        }
        finally
        {
            context.ConfigurationPath = null;
            this._initContext.ApplicationInstance = null;
            this._initContext = null;
        }
    }
    catch
    {
        throw;
    }
}


附: Application Events

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: