asp.net 运行原理

主要类:
  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 运行原理

分析:

当我们通过浏览器向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

asp.net 运行原理