开篇:上一篇我们了解了一个请求从客户端发出到服务端接收并转到ASP.Net处理入口的过程,这篇我们开始探索ASP.Net的核心处理部分,借助强大的反编译工具,我们会看到几个熟悉又陌生的名词(类):HttpRuntime、HttpWorkerRequest、HttpContext、HttpApplication等。
(1)Part 1:前奏
(2)Part 2:核心
(3)Part 3:管道
(4)Part 4:WebForm页面生命周期
(5)Part 5:MVC页面声命周期
一、第一个入口:ISAPIRuntme.ProcessRequest()
ISAPIRuntime是进入NET托管环境的入口,它在方法中通过一个ecb句柄指向了当前请求报文体的内存地址,将HTTP请求报文简单封装为一个HttpWorkerRequest对象,然后就是各种我们经常听到的PR(ProcessRequest)方法了。
①调用ISAPIRuntime对象的ProcessRequest方法进入ASP.NET处理流程
通过Reflector,我们可以看到在ISAPIRuntime中的这个入口方法:ProcessRequest
②首先根据ecb句柄创建HttpWorkerRequest对象封装原始请求报文
关于HttpWorkerRequest:
在Asp.Net中准备用于处理的请求,都必须封装为HttpWorkerRequest类型的对象,HttpWorkerRequest是一个抽象类型。这里创建的是一个ISAPIWorkerRequest类型,它继承于HttpWorkerRequest类。
[ComVisible(false)] public abstract class HttpWorkerRequest { // Fields private DateTime _startTime; private Guid _traceId; ...... }
转到ISAPIWorkerRequest类的CreateWorkerRequest方法中,看到首先判断当前IIS服务器的版本(IIS6 or IIS7?),然后创建适合不同IIS的具体WorkerRequest对象,默认都是InProc进程内的,当然,也有OutOfProc进程外的。
internal static ISAPIWorkerRequest CreateWorkerRequest(IntPtr ecb, bool useOOP) { if (useOOP) { EtwTrace.TraceEnableCheck(EtwTraceConfigType.DOWNLEVEL, IntPtr.Zero); if (EtwTrace.IsTraceEnabled(5, 1)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_APPDOMAIN_ENTER, ecb, Thread.GetDomain().FriendlyName, null, false); } return new ISAPIWorkerRequestOutOfProc(ecb); } int num = UnsafeNativeMethods.EcbGetVersion(ecb) >> 0x10; if (num >= 7) { EtwTrace.TraceEnableCheck(EtwTraceConfigType.IIS7_ISAPI, ecb); } else { EtwTrace.TraceEnableCheck(EtwTraceConfigType.DOWNLEVEL, IntPtr.Zero); } if (EtwTrace.IsTraceEnabled(5, 1)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_APPDOMAIN_ENTER, ecb, Thread.GetDomain().FriendlyName, null, true); } if (num >= 7) { return new ISAPIWorkerRequestInProcForIIS7(ecb); } if (num == 6) { return new ISAPIWorkerRequestInProcForIIS6(ecb); } return new ISAPIWorkerRequestInProc(ecb); }
由于HttpWorkerRequest类封装的请求报文很原始,很复杂,所以微软没有将其公开出来。
二、第二个入口:HttpRuntime.ProcessRequest()
HttpRuntime是ASP.NET请求处理的第二个入口。当请求进来,首先进入HttpRuntime,由HttpRuntime来决定如何处理请求。默认情况下,在machine.config和Web.config中并没有显式定义httpRuntime节点,但该节点是有默认值的,如下:
<httpRuntime apartmentThreading="false" appRequestQueueLimit="5000" delayNotificationTimeout="5" enable="true" enableHeaderChecking="true" enableKernelOutputCache="true" enableVersionHeader="true" encoderType = "System.Web.Util.HttpEncoder" executionTimeout="110" maxQueryStringLength = "2048" maxRequestLength="4096" maxUrlLength = "260" maxWaitChangeNotification="0" minFreeThreads="8" minLocalRequestFreeThreads="4" relaxedUrlToFileSystemMapping = "False" requestLengthDiskThreshold="80" requestPathInvalidCharacters = "<,>,*,%,&,:,\" requestValidationMode = "4.0" requestValidationType = "System.Web.Util.RequestValidator" requireRootedSaveAsPath="true" sendCacheControlHeader="true" shutdownTimeout="90" useFullyQualifiedRedirectUrl="false" waitChangeNotification="0" />
通常情况下,我们可以在Web.config中更改httpRuntime节点的默认值,如下: