ASP.NET从源码看实现(三):HttpApplication
IIS处理流程:HttpApplication
当HttpApplication对象经由HttpApplicationFactory.GetApplicationInstance方法从HttpApplication对象池中获取到实例后,直接调用了 state.InitInternal(context, this._state, this._eventHandlerMethods)方法;
InitInternal方法的主要功能如下:
1.InitIntegratedModules():会加载IIS7集成模式下在服务器上设定的HttpModuels和Web.config里system.webserver下的HttpModuels。
2. InitModules():根据Web.Config的设置,创建相应的HttpModules。
3. HookupEventHandlersForAppplicationAndModules:根据发生的事件,调用HttpApplication实例中相应的事件处理函数。
4.
创建很多实现IExecutionStep接口的类的实例并添加到当前HttpApplication实例的_execSteps中,等待回调时执行。从
这里我们可以看到HttpApplication是以异步的方式处理请求, 对请求的很多处理工作都放入了 _execStep等待回调时执行。
_execStep中主要的处理工作如下:
1) 对请求的路径进行安全检查,禁止非法路径访问(ValidatePathExecutionStep)。
2) 如果设置了UrlMappings, 进行RewritePath(UrlMappingsExecutionStep)。
3) 执行事件处理函数,比如:BeginRequest、AuthenticateRequest等等。
InitInternal方法也是一个比较复杂的方法,里面对于IIS采用的是Integrated(集成)模式还是Classic(经典)模式进行分别的处理,主要完成的工作时HttpModule的初始化和处理请求过程中每个步骤触发事件处理程序的准备。 在经典模式下,IIS会用ISAPI扩展(ISAPI extension aspnet_isapi.dll)和 ISAPI过滤器(ISAPI filter aspnet_filter.dll)来调用ASP.NET运行库来出来请求。如果使用经典模式的话,服务器会用两种管道来处理请求一个负责源代码,另外一个负责托管代码。在这种模式下,应用程序不能充分使用IIS7.X提供的服务。
集成模式是一种统一的请求处理管道,它将ASP.NET请求管道与IIS核心管道组合在一起。在集成模式下,ASP.NET从IIS插件(IIS extension)的角色进入了IIS的核心去监测每个请求和操作。在集成模式下,ASP.NET能更有效的在IIS下运行,并且可以有效的提高网站的性能。
关于IIS的经典模式与集成模式的详细介绍请参考 IIS 7.0的集成模式和经典模式
///HttpApplication类 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();//Integrate模式下Module的初始化 goto Label_006B; } finally { context.HideRequestResponse = false; this._hideRequestResponse = false; } } this.InitModules();//根据Web.Config的设置,创建相应的HttpModules 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);//Integrate模式下 } 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; } }
在 this.InitModules()方法中首先加载配置文件中所有的HttpModule,当获取到所有的HttpModule集合后在InitModulesCommon方法中循环调用每个HttpModule的Init方法;
private void InitModules() { HttpModuleCollection modules = RuntimeConfig.GetAppConfig().HttpModules.CreateModules(); HttpModuleCollection other = this.CreateDynamicModules(); modules.AppendCollection(other); this._moduleCollection = modules; 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(); }
对应this.HookupEventHandlersForApplicationAndModules(handlers)方法就是调用Global.asax中的方法相关实现的事件;
StepManager类是一个管理Step的抽象类,他的抽象方法BuildSteps就是将HTTP的管道时间添加到HttpApplication.IExecutionStep[] _execSteps,等待回调;
//ApplicationStepManager : HttpApplication.StepManager 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(app.CreateImplicitAsyncPreloadExecutionStep()); 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; }
- 对请求的Request进行验证,ValidateRequestExecutionStep。
- 对请求的路径进行安全检查,禁止非法路径访问(ValidatePathExecutionStep)。
- 如果设置了UrlMappings, 进行RewritePath(UrlMappingsExecutionStep)。
- 执行事件处理函数,比如将BeginRequest、AuthenticateRequest转化成可执行ExecutionStep在正式调用时候执行。
- 在这18个事件操作处理期间,根据不同的时机加了4个特殊的ExecutionStep。
- MapHandlerExecutionStep:查找匹配的HttpHandler
- CallHandlerExecutionStep:执行HttpHandler的BeginProcessRequest
- CallFilterExecutionStep:调用Response.FilterOutput方法过滤输出
- NoopExecutionStep:空操作,留着以后扩展用
需要注意的是所有的ExecuteionStep都保存在ApplicationStepManager实例下的私有字段_execSteps里, 而HttpApplication的BeginProcessRequest方法最终会通过该实例的ResumeSteps方法来执行这些操作(就是我们 所说的那些事件以及4个特殊的Steps)。
具体这个方法的实现可以参考汤姆大叔写的MVC之前的那点事儿系列(5):Http Pipeline详细分析(下)这个博客;
至此,当HttpApplication的InitInternal方法执行完后,整个HttpApplication就从HttpApplicationFactory工厂中创建完成,并返回到HttpRuntime.ProcessRequestInternal方法中;