为什么要了解这些底层呢?我觉得做为一个喜欢开发ASP.NET程序员,我不们不仅要知道“怎么做”,我们更应该知道“为什么这么做”,这样的我们才能做得更好。这样我们才能把准确的代码放置准确的位置。
ASP.NET 像一个全自动的洗车房,车开进车房并通过层层洗刷,最后出来一部闪亮的车。
IIS维护着一个映射表(图1)用来指定:什么样的请求由什么程序来处理该请求,比如说:所请求资源的扩展名为.asp的请求,由"asp.dll" 处理该请求,这个“DLL”文件称为ISAPI扩展程序。
当一个请求从浏览器发出,到达服务器端,IIS收到该请求。IIS根据所请求资源的扩展名,将该请求转交给相应的ISAPI扩展程序来处理。那扩展名为.aspx的请求是怎么样的呢?同样也是由相应的ISAPI处理该请求,也就是aspnet_isapi.dll,但这只是第一站,aspnet_isapi 还要将该请求转交给ASP.NET来处理。如下图(2)。
(图2)
IIS运行在一个InetInfo.exe的进程中,IIS收到扩展名为.aspx请求后,加载ASP.NET ISAPI---"aspnet_isapi.dll",ASP.NET ISAPI 会启动一个名为"aspnet_wp.exe"的工作进程,“aspnet_wp.exe”启动时会加载CLR、创建appDomain,在创建对appDomain时会实例化一个名为ISAPIRuntime类,ISAPIRuntime是Asp.net与asp.net ISAPI通信的桥梁。IIS与ASP.NET ISAPI都是非托管程序,而ASP.NET HttpRuntime则是一个托管程序,ASP.NET ISAPI 通过COM的方式与ASP.NET Http Runtime基于命名管道通信。ISAPIRuntime是一个特殊的类,它实现接口IISAPIRuntime,该接口基于COM。所以说非托管程序可以以COM的方式访问。
[ComImport, Guid("08a2c56f-7c16-41c1-a8be-432917a1a2d1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IISAPIRuntime
{
void StartProcessing();
void StopProcessing();
[return: MarshalAs(UnmanagedType.I4)]
int ProcessRequest([In] IntPtr ecb, [In, MarshalAs(UnmanagedType.I4)] int useProcessModel);
void DoGCCollect();
}
ASP.NET ISAPI 调用 ISAPIRumtime ProcessRequest 方法的,这时就到了托管环境的天下,到ASP.NET发挥的时候了,个个“洗刷”工具开始启动。
public int ProcessRequest(IntPtr ecb, int iWRType)
{
int num;
try
{
HttpWorkerRequest wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, iWRType);
string appPathTranslated = wr.GetAppPathTranslated();
string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal;
if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
{
HttpRuntime.ProcessRequestNoDemand(wr);
return 0;
}
HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString("Hosting_Phys_Path_Changed", new object[] { appDomainAppPathInternal, appPathTranslated }));
num = 1;
}
catch (Exception exception)
{
Misc.ReportUnhandledException(exception, new string[] { SR.GetString("Failed_to_process_request") });
throw;
}
return num;
}
ISAPIRuntime将处理权转交给HttpRumtime的ProcessRequestInternal方法
private void ProcessRequestInternal(HttpWorkerRequest wr)
{
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;
}
}
extraData.Response.InitResponseWriter();
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);
}
}