Asp.net请求处理之管道处理介绍

时间:2021-10-10 19:46:03

在了解Asp.net请求处理流程的过程中,个人认为有必要从源代码的角度来了解asp.net管道是怎么实现的。 

在此之前大家有必要了解一些asp.net请求流程的基本东东,如ASP.NET 请求处理流程、Asp.net管道、ASP.NET管线与应用程序生命周期 

我们大家都知道HttpRuntime主要的方法是 

public static void ProcessRequest(HttpWorkerRequest 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(5, 1)) 

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

}


我们看到里面有这么一句 

IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);用来获取HttpApplication,而HttpApplication实现了IHttpAsyncHandler接口public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable,最后调用application的BeginProcessRequest方法。 
HttpApplicationFactory.GetApplicationInstance(context)主要是调用GetNormalApplicationInstance 

复制代码代码如下:


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


在GetNormalApplicationInstance里面有一个比较关键的方法application.InitInternal(context, this._state, this._eventHandlerMethods);我们猜测它是做Application初始化的工作,包括http管道的初始化。 

复制代码代码如下:


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; 

}


这个方法关键的代码在于: 

复制代码代码如下:


if (HttpRuntime.UseIntegratedPipeline) 

this._stepManager = new PipelineStepManager(this); 

else 

this._stepManager = new ApplicationStepManager(this); 

this._stepManager.BuildSteps(this._resumeStepsWaitCallback); 


我想大家看到这里就会明白为什么IIS7会有集成模式和经典模式了吧。可能大家不怎么重视此代码,让我们来看看经典模式的ApplicationStepManager 

复制代码代码如下:


internal class ApplicationStepManager : HttpApplication.StepManager 

// Fields 
private int _currentStepIndex; 
private int _endRequestStepIndex; 
private HttpApplication.IExecutionStep[] _execSteps; 
private int _numStepCalls; 
private int _numSyncStepCalls; 
private WaitCallback _resumeStepsWaitCallback; 

// Methods 
internal ApplicationStepManager(HttpApplication app) : base(app) 



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; 


internal override void InitRequest() 

this._currentStepIndex = -1; 
this._numStepCalls = 0; 
this._numSyncStepCalls = 0; 
base._requestCompleted = false; 


[DebuggerStepperBoundary] 
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 

context2 = application.OnThreadEnter(); 

catch (Exception exception) 

if (error == null) 

error = exception; 


try 

try 

Label_0045: 
if (syncContext.Error != null) 

error = syncContext.Error; 
syncContext.ClearError(); 

if (error != null) 

application.RecordError(error); 
error = null; 

if (syncContext.PendingOperationsCount > 0) 

syncContext.SetLastCompletionWorkItem(this._resumeStepsWaitCallback); 

else 

if ((this._currentStepIndex < this._endRequestStepIndex) && ((context.Error != null) || base._requestCompleted)) 

context.Response.FilterOutput(); 
this._currentStepIndex = this._endRequestStepIndex; 

else 

this._currentStepIndex++; 

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 

if (context2 != null) 

try 

context2.Leave(); 

catch 





catch 

throw; 


if (flag) 

context.Unroot(); 
application.AsyncResult.Complete(this._numStepCalls == this._numSyncStepCalls, null, null); 
application.ReleaseAppInstance(); 


}


说简单一点这个类中的internal override void BuildSteps(WaitCallback stepCallback)方法就是为我们注册那19个管道事件, internal override void ResumeSteps(Exception error)就是依次执行此管道事件,而 steps.Add(new HttpApplication.MapHandlerExecutionStep(app));是映射我们的handler 

复制代码代码如下:


internal class MapHandlerExecutionStep : HttpApplication.IExecutionStep 

// Fields 
private HttpApplication _application; 

// Methods 
internal MapHandlerExecutionStep(HttpApplication app) 

this._application = app; 


void HttpApplication.IExecutionStep.Execute() 

HttpContext context = this._application.Context; 
HttpRequest request = context.Request; 
if (EtwTrace.IsTraceEnabled(5, 1)) 

EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_ENTER, context.WorkerRequest); 

context.Handler = this._application.MapHttpHandler(context, request.RequestType, request.FilePathObject, request.PhysicalPathInternal, false); 
if (EtwTrace.IsTraceEnabled(5, 1)) 

EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_LEAVE, context.WorkerRequest); 



// Properties 
bool HttpApplication.IExecutionStep.CompletedSynchronously 

get 

return true; 



bool HttpApplication.IExecutionStep.IsCancellable 

get 

return false; 


}


里面的调用主要是 

context.Handler = this._application.MapHttpHandler(context, request.RequestType, request.FilePathObject, request.PhysicalPathInternal, false); 

而HttpApplication的MapHttpHandler如下: 

复制代码代码如下:


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 (FileNotFoundException exception) 

if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated)) 

throw new HttpException(0x194, null, exception); 

throw new HttpException(0x194, null); 

catch (DirectoryNotFoundException exception2) 

if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated)) 

throw new HttpException(0x194, null, exception2); 

throw new HttpException(0x194, null); 

catch (PathTooLongException exception3) 

if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated)) 

throw new HttpException(0x19e, null, exception3); 

throw new HttpException(0x19e, null); 

if (this._handlerRecycleList == null) 

this._handlerRecycleList = new ArrayList(); 

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

return handler; 
}


在MapHttpHandler里创建了IHttpHandlerFactory,进而创建了httphandler。 

在ApplicationStepManager中BuildSteps的方法有steps.Add(new HttpApplication.CallHandlerExecutionStep(app));这么一句,这就是注册调用我们hanndler的地方。 

复制代码代码如下:


internal class CallHandlerExecutionStep : HttpApplication.IExecutionStep 

// Fields 
private HttpApplication _application; 
private AsyncCallback _completionCallback; 
private IHttpAsyncHandler _handler; 
private bool _sync; 

// Methods 
internal CallHandlerExecutionStep(HttpApplication app) 

this._application = app; 
this._completionCallback = new AsyncCallback(this.OnAsyncHandlerCompletion); 


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) 

if ((exception2 is ThreadAbortException) || ((exception2.InnerException != null) && (exception2.InnerException is ThreadAbortException))) 

this._application.CompleteRequest(); 

else 

error = exception2; 


if (EtwTrace.IsTraceEnabled(4, 4)) 

EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_LEAVE, context.WorkerRequest); 

this._handler = null; 
context.SetStartTime(); 
if (HttpRuntime.IsLegacyCas) 

this.ResumeStepsWithAssert(error); 

else 

this.ResumeSteps(error); 




private void ResumeSteps(Exception error) 

this._application.ResumeStepsFromThreadPoolThread(error); 


[PermissionSet(SecurityAction.Assert, Unrestricted=true)] 
private void ResumeStepsWithAssert(Exception error) 

this.ResumeSteps(error); 


void HttpApplication.IExecutionStep.Execute() 

HttpContext context = this._application.Context; 
IHttpHandler handler = context.Handler; 
if (EtwTrace.IsTraceEnabled(4, 4)) 

EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_ENTER, context.WorkerRequest); 

if ((handler != null) && HttpRuntime.UseIntegratedPipeline) 

IIS7WorkerRequest workerRequest = context.WorkerRequest as IIS7WorkerRequest; 
if ((workerRequest != null) && workerRequest.IsHandlerExecutionDenied()) 

this._sync = true; 
HttpException exception = new HttpException(0x193, SR.GetString("Handler_access_denied")); 
exception.SetFormatter(new PageForbiddenErrorFormatter(context.Request.Path, SR.GetString("Handler_access_denied"))); 
throw exception; 


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

if (EtwTrace.IsTraceEnabled(4, 4)) 

EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_LEAVE, context.WorkerRequest); 



else 

this._sync = true; 
context.SyncContext.SetSyncCaller(); 
try 

handler.ProcessRequest(context); 

finally 

context.SyncContext.ResetSyncCaller(); 
if (EtwTrace.IsTraceEnabled(4, 4)) 

EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_LEAVE, context.WorkerRequest); 

context.Response.GenerateResponseHeadersForHandler(); 




// Properties 
bool HttpApplication.IExecutionStep.CompletedSynchronously 

get 

return this._sync; 



bool HttpApplication.IExecutionStep.IsCancellable 

get 

return !(this._application.Context.Handler is IHttpAsyncHandler); 


}


在代码中我们看到handler2.BeginProcessRequest(context, this._completionCallback, null);。。。handler.ProcessRequest(context);这2句代码是不是很熟悉啊。 

在让我们回头看看HttpApplication的BeginProcessRequest方法 

复制代码代码如下:


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


里面调用了ResumeSteps方法 

复制代码代码如下:


private void ResumeSteps(Exception error) 

this._stepManager.ResumeSteps(error); 


回到我们先前的ApplicationStepManager的ResumeSteps方法,里面有一句 

error = application.ExecuteStep(this._execSteps[this._currentStepIndex], ref completedSynchronously); 

Ahhpaplication的ExecuteStep方法 

复制代码代码如下:


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) 

exception = exception2; 
if (ImpersonationContext.CurrentThreadTokenExists) 

exception2.Data["ASPIMPERSONATING"] = string.Empty; 

if ((exception2 is ThreadAbortException) && ((Thread.CurrentThread.ThreadState & ThreadState.AbortRequested) == ThreadState.Running)) 

exception = null; 
this._stepManager.CompleteRequest(); 


catch 



catch (ThreadAbortException exception3) 

if ((exception3.ExceptionState != null) && (exception3.ExceptionState is CancelModuleException)) 

CancelModuleException exceptionState = (CancelModuleException) exception3.ExceptionState; 
if (exceptionState.Timeout) 

exception = new HttpException(SR.GetString("Request_timed_out"), null, 0xbb9); 
PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_TIMED_OUT); 

else 

exception = null; 
this._stepManager.CompleteRequest(); 

Thread.ResetAbort(); 


completedSynchronously = true; 
return exception; 
}


是真正执行IExecutionStep的Execute方法。 

通过以上的分析我们可以简单的理解asp.net在管道模式下管道主要是通过ApplicationStepManager来注册和调用的。集成模式下的PipelineStepManager和ApplicationStepManager结构类似。 

个人在这里只是抛砖引玉,希望大家拍砖。

相关文章