上一篇讲了从创建应用程序域到创建 ISAPIRuntime 实例的过程,本篇继续讲 Asp.net 处理第一次请求的必要的初始化过程。
ISAPIRuntime 在 System.Web.Hosting 中实现,它的 ProcessRequest 是我们处理 web 请求的入口。
- public intProcessRequest(IntPtr ecb,int iWRType) {
- IntPtr pHttpCompletion = IntPtr.Zero;
- if(iWRType == WORKER_REQUEST_TYPE_IN_PROC_VERSION_2) {
- pHttpCompletion = ecb;
- ecb = UnsafeNativeMethods.GetEcb(pHttpCompletion);
- }
- ISAPIWorkerRequest wr =null;
- try {
- booluseOOP = (iWRType == WORKER_REQUEST_TYPE_OOP);
- wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
- wr.Initialize();
- String wrPath = wr.GetAppPathTranslated();
- String adPath = HttpRuntime.AppDomainAppPathInternal;
- if(adPath ==null||StringUtil.EqualsIgnoreCase(wrPath, adPath)) {
- HttpRuntime.ProcessRequestNoDemand(wr);
- return 0;
- }
- else {
- HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString(SR.Hosting_Phys_Path_Changed, adPath, wrPath));
- return 1;
- }
- }
- catch(Exception e) {
- try {
- WebBaseEvent.RaiseRuntimeError(e, this);
- } catch {}
- if(wr !=null&& wr.Ecb == IntPtr.Zero) {
- if(pHttpCompletion != IntPtr.Zero) {
- UnsafeNativeMethods.SetDoneWithSessionCalled(pHttpCompletion);
- }
- if(eis ThreadAbortException) {
- Thread.ResetAbort();
- }
- return 0;
- }
- throw;
- }
- }
注意方法的 IntPtr 类型的参数 ecb, 它是一个非托管的指针,用于传递一些必须的数据,以及最终将 Response 的内容返回给非托管环境 ISAPI(异步方式),然后呈现给 Client 用户。方法中调用 ISAPIWorkerRequest 的静态方法 CreateWorkerRequest 而创建 ISAPIWorkerRequest 对象实例,参数分别为 ecb 和代表 WorkerRequest 类型的 int 参数 iWRType,通过判断 ecb 和 type 类型的具体内容,来决定创建什么类型的 WorkerRequest(上述类型的 ISPAIWorkerRequest 都继承于 HttpWorkerRequest),上面的代码可以看出对不同版本的 IIS 进行了不同的包装,通过其 Initialize 方法来初始化一些基本的信息(比如:contentType, querystring 的长度,filepath 等相关信息)。然后调用 HttpRuntime.ProcessRequestNoDemand(wr) 转入 HttpRuntime 处理请求,最终体现在调用 ProcessRequestInternal 方法上。
Httpruntime 在 System.Web 下实现,我们来看其处理请求的 ProcessRequestInternal 方法。
- private void ProcessRequestInternal(HttpWorkerRequest wr) {
- Interlocked.Increment(ref _activeRequestCount);
- if (_disposingHttpRuntime) {
- try {
- wr.SendStatus(503,"Server Too Busy");
- wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8");
- byte[] body = Encoding.ASCII.GetBytes("<html><body>Server Too Busy</body></html>");
- wr.SendResponseFromMemory(body, body.Length);
- wr.FlushResponse(true);
- wr.EndOfRequest();
- } finally {
- Interlocked.Decrement(ref _activeRequestCount);
- }
- return;
- }
- HttpContext context;
- try {
- context =newHttpContext(wr,false);
- }
- catch {
- try {
- wr.SendStatus(400,"Bad Request");
- wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8");
- byte[] body = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
- wr.SendResponseFromMemory(body, body.Length);
- wr.FlushResponse(true);
- wr.EndOfRequest();
- return;
- } finally {
- Interlocked.Decrement(ref _activeRequestCount);
- }
- }
- wr.SetEndOfSendNotification(_asyncEndOfSendCallback, context);
- HostingEnvironment.IncrementBusyCount();
- try {
- try {
- EnsureFirstRequestInit(context);
- }
- catch {
- if(!context.Request.IsDebuggingRequest) {
- throw;
- }
- }
- context.Response.InitResponseWriter();
- IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);
- if(app ==null)
- throw new HttpException(SR.GetString(SR.Unable_create_app_object));
- if(EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, app.GetType().FullName,"Start");
- if(appis IHttpAsyncHandler) {
- IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)app;
- context.AsyncAppHandler = asyncHandler;
- asyncHandler.BeginProcessRequest(context, _handlerCompletionCallback, context);
- }
- else {
- app.ProcessRequest(context);
- FinishRequest(context.WorkerRequest, context, null);
- }
- }
- catch (Exception e) {
- context.Response.InitResponseWriter();
- FinishRequest(wr, context, e);
- }
- }
该方法中创建了熟悉的 HttpContext 并同时创建了 HttpRequest 与 HttpResponse
- internalHttpContext(HttpWorkerRequest wr,bool initResponseWriter) {
- _wr = wr;
- Init(newHttpRequest(wr,this),newHttpResponse(wr,this));
- if (initResponseWriter)
- _response.InitResponseWriter();
- PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_EXECUTING);
- }
然后通过 HttpApplicationFactory 的 GetApplicationInstance 静态方法,获取我们熟悉的 HttpApplication 对象实例(注:HttpApplication 对象是继承 IHttpAsyncHandler,而 IHttpAsyncHandler 又继承于 IHttpHandler),然后执行调用 BeginProcessRequest 方法。至此正式进入了 HttpApplication 对象的创建以及大家熟知的 HttpApplication 以后的生命周期了。
HttpApplicationFactory 在 System.Web 下实现。
查看 HttpApplicationFactory 用来创建 Httpapplication 的 GetApplicationInstance 方法。
- 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);
- }
该方法有三个步骤:首先是 EnsureInited,会检查是否已经初始化,如果没有会调用 Init 方法先获取 global.asax 文件的完整路径,然后调用 CompileApplication() 对 global.asax 进行编译,Init 方法如下。
- private void Init() {
- if(_customApplication !=null)
- return;
- try {
- try {
- _appFilename = GetApplicationFile();
- CompileApplication();
- }
- finally {
- SetupChangesMonitor();
- }
- }
- catch {
- throw;
- }
- }
然后是 EnsureAppStartCalled 方法如果未开始启动会调用 FireApplicationOnStart。
- private void EnsureAppStartCalled(HttpContext context) {
- if(!_appOnStartCalled) {
- lock(this) {
- if(!_appOnStartCalled) {
- using(new DisposableHttpContextWrapper(context)) {
- WebBaseEvent.RaiseSystemEvent(this, WebEventCodes.ApplicationStart);
- FireApplicationOnStart(context);
- }
- _appOnStartCalled =true;
- }
- }
- }
- }
- private void FireApplicationOnStart(HttpContext context) {
- if(_onStartMethod !=null) {
- HttpApplication app = GetSpecialApplicationInstance();
- app.ProcessSpecialRequest(context, _onStartMethod, _onStartParamCount, this, EventArgs.Empty,null);
- RecycleSpecialApplicationInstance(app);
- }
- }
这里创建特定的 HttpApplication 实例,触发 ApplicationOnStart 事件 (会执行 global.asax 中的 Application_Start 方法)。然后在处理完事件以后就立即被回收掉,因为系统初始化只需要一次。
最后是 GetNormalApplicationInstance,如果在有空闲的 HttpApplication 实例,就直接用,如果没有就新创建,然后调用 InitInternal 方法进行初始化相关的内容,最后返回该 HttpApplication 实例。
- private HttpApplication GetNormalApplicationInstance(HttpContext context) {
- HttpApplication app =null;
- lock (_freeList) {
- if(_numFreeAppInstances >0) {
- app = (HttpApplication)_freeList.Pop();
- _numFreeAppInstances--;
- if(_numFreeAppInstances < _minFreeAppInstances) {
- _minFreeAppInstances = _numFreeAppInstances;
- }
- }
- }
- if(app ==null) {
- app = (HttpApplication)HttpRuntime.CreateNonPublicInstance(_theApplicationType);
- using(new ApplicationImpersonationContext()) {
- app.InitInternal(context, _state, _eventHandlerMethods);
- }
- }
- ……
- return app;
- }
HttpApplication 在 System.Web 下实现,首先查看 HttpApplication 的 InitInternal 方法,该方法用于初始化。
- internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) {
- Debug.Assert(context !=null,"context != null");
- _state = state;
- PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES);
- try {
- try {
- _initContext = context;
- _initContext.ApplicationInstance =this;
- context.ConfigurationPath = context.Request.ApplicationPathObject;
- using(new DisposableHttpContextWrapper(context)) {
- if (HttpRuntime.UseIntegratedPipeline) {
- Debug.Assert(_moduleConfigInfo !=null,"_moduleConfigInfo != null");
- Debug.Assert(_moduleConfigInfo.Count >=0,"_moduleConfigInfo.Count >= 0");
- try {
- context.HideRequestResponse =true;
- _hideRequestResponse =true;
- InitIntegratedModules();
- }
- finally {
- context.HideRequestResponse =false;
- _hideRequestResponse =false;
- }
- }
- else {
- InitModules();
- Debug.Assert(null== _moduleContainers,"null == _moduleContainers");
- }
- if(handlers !=null)
- HookupEventHandlersForApplicationAndModules(handlers);
- _context = context;
- if(HttpRuntime.UseIntegratedPipeline && _context !=null) {
- _context.HideRequestResponse =true;
- }
- _hideRequestResponse =true;
- try {
- Init();
- }
- catch (Exception e) {
- RecordError(e);
- }
- }
- if(HttpRuntime.UseIntegratedPipeline && _context !=null) {
- _context.HideRequestResponse =false;
- }
- _hideRequestResponse =false;
- _context =null;
- _resumeStepsWaitCallback=newWaitCallback(this.ResumeStepsWaitCallback);
- if (HttpRuntime.UseIntegratedPipeline) {
- _stepManager =newPipelineStepManager(this);
- }
- else {
- _stepManager =newApplicationStepManager(this);
- }
- _stepManager.BuildSteps(_resumeStepsWaitCallback);
- }
- finally {
- _initInternalCompleted =true;
- context.ConfigurationPath =null;
- _initContext.ApplicationInstance =null;
- _initContext =null;
- }
- }
- catch {
- throw;
- }
- }
该代码主要有 2 个功能,一个是初始化大家熟悉的 HttpModules,一个是通过 BuildSteps 执行多个生命周期事件的处理函数。通过上面的代码我们可以看出,每个功能都有一个特殊判断,判断 IIS 是否是 IIS7 的集成模式,如果是就有特殊的步骤,如果不是就走一般的步骤(两者直接的差异分别是:经典模式初始化 HttpModules 的时候会从网站配置的 Modules 里读取,集成模式会预加载 CLR 和大量 Modules,比如加载服务器上设置的 HttpModules;另外在 BuildSteps 的时候, IIS7 集成模式走的是自己特殊的流程)。
总结一下,InitInternal 方法的主要功能如下:
InitModules():根据 Web.Config 的设置,加载相应的 HttpModules。
InitIntegratedModules():会加载 IIS7 集成模式下在服务器上设定的 HttpModuels 和 Web.config 里 system.webserver 下的 HttpModuels。
HookupEventHandlersForAppplicationAndModules:绑定 HttpApplication 实例中相应的事件处理函数(在 Global.asax 中定义的事件处理函数)。
创建很多实现 IExecutionStep 接口的类的实例并添加到当前 HttpApplication 实例的_execSteps 中(包括 HttpModules 中定义的周期事件处理函数和查找匹配的 HttpHandler、执行 HttpHandler 的方法以及过滤输出等特殊事件),等待回调时执行。从这里我们可以看到 HttpApplication 是以异步的方式处理请求, 对请求的很多处理工作都放入了_execStep 等待回调时执行。
在 HttpApplication 的事件如下形式定义:
- public event EventHandler BeginRequest {
- add {
- AddSyncEventHookup(EventBeginRequest, value, RequestNotification.BeginRequest);
- }
- remove {
- RemoveSyncEventHookup(EventBeginRequest, value, RequestNotification.BeginRequest);
- }
- }
所有的事件都是调用 AddSyncEventHookup 方法添加进去的,其中第一个参数是以 Event + 事件名称的值。
- internal voidAddSyncEventHookup(object key, Delegate handler, RequestNotification notification) {
- AddSyncEventHookup(key, handler, notification, false);
- }
- private voidAddSyncEventHookup(objectkey, Delegate handler, RequestNotification notification,bool isPostNotification) {
- ThrowIfEventBindingDisallowed();
- Events.AddHandler(key, handler);
- if (IsContainerInitalizationAllowed) {
- PipelineModuleStepContainer container = GetModuleContainer(CurrentModuleCollectionKey);
- if(container !=null) {
- SyncEventExecutionStep step =newSyncEventExecutionStep(this, (EventHandler)handler);
- container.AddEvent(notification, isPostNotification, step);
- }
- }
- }
经典模式下在初始化 HttpModlue 的时候通过调用 Events.AddHandler 方法,将事件添加到 Events 集合里,同时这个 key 就是 Event + 事件名称,而集成模式下这些事件是添加到另外一个地方的(通过将事件 hanlder 包装成 SyncEventExecutionStep 类型,然后调用 container.AddEvent 方法将事件添加到另外一个地方),也就是说 if 上面的 Events 集合是给经典模式用的,下面的 Container 里的数据是给集成模式用的,这些事件是存放在 HttpApplication 的 ModuleContainers 属性里,这个属性的类型是 PipelineModuleStepContainer[],个数就是 HttpModules 的个数,也就是说每个 HttpModule 在 HttpApplication 上添加的事件都放在各自的 PipelineModuleStepContainer 容器里。
- private PipelineModuleStepContainer[] ModuleContainers {
- get {
- if(_moduleContainers ==null) {
- Debug.Assert(_moduleIndexMap !=null&& _moduleIndexMap.Count >0,"_moduleIndexMap != null && _moduleIndexMap.Count > 0");
- _moduleContainers =new PipelineModuleStepContainer[_moduleIndexMap.Count];
- for(inti =0; i < _moduleContainers.Length; i++) {
- _moduleContainers[i] =new PipelineModuleStepContainer();
- }
- }
- return _moduleContainers;
- }
- }
集成模式和经典模式(或 IIS6)使用的是不同的 StepManager,这个类的 BuildSteps 方法就是为了创建有序的 ExecutionStep,其中包括各种事件的事情以及其它在各时间周期之间穿插的操作,最主要的操作,大家以前就应该知道的,比如哪个周期可以判定使用哪个 HttpHandler,以及在哪个周期内执行这个 HttpHandler 的 BeginProcessRequest 方法。StepManager 的具体实现类(ApplicationStepManager、PipelineStepManager)和 HttpApplication 类在同一个文件中定义。
ApplicationStepManager 的 BuildSteps 方法(用于经典模式)
- internal override void BuildSteps(WaitCallback stepCallback ) {
- ArrayList steps =new ArrayList();
- HttpApplication app = _application;
- boolurlMappingsEnabled =false;
- UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;
- urlMappingsEnabled = urlMappings.IsEnabled && ( urlMappings.UrlMappings.Count >0 );
- steps.Add(new ValidateRequestExecutionStep(app));
- steps.Add(new ValidatePathExecutionStep(app));
- if (urlMappingsEnabled)
- steps.Add(newUrlMappingsExecutionStep(app));// url mappings
- 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(newMapHandlerExecutionStep(app));// map handler
- 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(newCallHandlerExecutionStep(app));// execute handler
- app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);
- app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);
- app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);
- steps.Add(newCallFilterExecutionStep(app));// filtering
- app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);
- app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);
- _endRequestStepIndex = steps.Count;
- app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);
- steps.Add(newNoopExecutionStep());// the last is always there
- _execSteps =new IExecutionStep[steps.Count];
- steps.CopyTo(_execSteps);
- _resumeStepsWaitCallback = stepCallback;
- }
- private void CreateEventExecutionSteps(Object eventIndex, ArrayList steps) {
- AsyncAppEventHandler asyncHandler = AsyncEvents[eventIndex];
- if(asyncHandler !=null) {
- asyncHandler.CreateExecutionSteps(this, steps);
- }
- EventHandler handler = (EventHandler)Events[eventIndex];
- if(handler !=null) {
- Delegate[] handlers = handler.GetInvocationList();
- for(inti =0; i < handlers.Length; i++) {
- steps.Add(newSyncEventExecutionStep(this, (EventHandler)handlers[i]));
- }
- }
- }
这个方法的完整功能归纳总结有以下几点:
对请求的 Request 进行验证,ValidateRequestExecutionStep。
对请求的路径进行安全检查,禁止非法路径访问 (ValidatePathExecutionStep)。
如果设置了 UrlMappings, 进行 RewritePath(UrlMappingsExecutionStep)。
执行事件处理函数,比如将 BeginRequest、AuthenticateRequest 转化成可执行 ExecutionStep 在正式调用时候执行。
在这多个个事件操作处理期间,根据不同的时机加了 4 个特殊的 ExecutionStep。
MapHandlerExecutionStep:查找匹配的 HttpHandler
CallHandlerExecutionStep:执行 HttpHandler 的 BeginProcessRequest
CallFilterExecutionStep:调用 Response.FilterOutput 方法过滤输出
NoopExecutionStep:空操作,留着以后扩展用
所有的 ExecuteionStep 都保存在 ApplicationStepManager 实例下的私有字段_execSteps 里,而 HttpApplication 的 BeginProcessRequest 方法最终会通过该实例的 ResumeSteps 方法来执行这些操作。
PipelineStepManager 的 BuildSteps(用于集成模式)
- internal override void BuildSteps(WaitCallback stepCallback) {
- Debug.Trace("PipelineRuntime","BuildSteps");
- HttpApplication app = _application;
- IExecutionStep materializeStep =new MaterializeHandlerExecutionStep(app);
- app.AddEventMapping(ttpApplication.IMPLICIT_HANDLER,
- RequestNotification.MapRequestHandler,
- false, materializeStep);
- app.AddEventMapping(HttpApplication.IMPLICIT_HANDLER,
- RequestNotification.ExecuteRequestHandler,
- false, app.CreateImplicitAsyncPreloadExecutionStep());
- IExecutionStep handlerStep =new CallHandlerExecutionStep(app);
- app.AddEventMapping(HttpApplication.IMPLICIT_HANDLER,
- RequestNotification.ExecuteRequestHandler,
- false, handlerStep);
- IExecutionStep webSocketsStep =new TransitionToWebSocketsExecutionStep(app);
- app.AddEventMapping(HttpApplication.IMPLICIT_HANDLER,
- RequestNotification.EndRequest,
- true, webSocketsStep);
- IExecutionStep filterStep =new CallFilterExecutionStep(app);
- app.AddEventMapping(HttpApplication.IMPLICIT_FILTER_MODULE,
- RequestNotification.UpdateRequestCache,
- false, filterStep);
- app.AddEventMapping(HttpApplication.IMPLICIT_FILTER_MODULE,
- RequestNotification.LogRequest,
- false, filterStep);
- _resumeStepsWaitCallback = stepCallback;
- }
- private voidAddEventMapping(string moduleName,RequestNotification requestNotification, bool isPostNotification,IExecutionStep step) {
- ......
- PipelineModuleStepContainer container = GetModuleContainer(moduleName);
- container.AddEvent(requestNotification, isPostNotification, step);
- }
以上代码有 2 个地方和经典模式不相同:
集成模式没有使用 MapHandlerExecutionStep 来装载 ExecutionStep(也就是查找对应的 HttpHandler),而是通过 MaterializeHandlerExecutionStep 类来获得 HttpHandler,方式不一样。
集成模式是通过 HttpApplication 的 AddEventMapping 方法来添加事件的,从而将事件加入到前面所说的 ModuleContainers 容器。
总结一下,在经典模式下,是用 Event + 事件名称做 key 将所有事件的保存在 HttpApplication 的 Events 属性对象里,然后在 BuildSteps 里统一按照顺序组装,中间加载 4 个特殊的 ExecutionStep,最后在统一执行;在集成模式下,是通过 HttpModule 名称 + RequestNotification 枚举值作为 key 将所有的事件保存在 HttpApplication 的 ModuleContainers 属性对象里,然后也在 BuildSteps 里通过伪造 HttpModule 名称加载那 4 个特殊的 ExecutionStep,最后按照枚举类型的顺序,遍历所有的 HttpModule 按顺序来执行这些事件,可以自行编写一个自定义的 HttpModuel 来执行这些事件看看效果如何。
下面是总结一下处理第一次请求的大体处理流程。
来源: http://www.cnblogs.com/ssxg/p/7085877.html