這些天看了一些關於ASP.NET底層的文章,受益匪淺。
為什麼要瞭解這些底層呢?我覺得做為一個喜歡開發ASP.NET程式員,我不們不僅要知道“怎麼做”,我們更應該知道“為什麼這麼做”,這樣的我們才能做得更好。這樣我們才能把準確的代碼放置準確的位置。
ASP.NET 像一個全自動的洗車房,車開進車房並通過層層洗刷,最後出來一部閃亮的車。
IIS維護著一個映射表(圖1)用來指定:什麼樣的請求由什麼程式來處理該請求,比如說:所請求資源的副檔名為.asp的請求,由"asp.dll" 處理該請求,這個“DLL”檔案稱為ISAPI擴充程式。
(圖1)
當一個請求從瀏覽器發出,到達伺服器端,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的方式訪問。
Code
[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發揮的時候了,個個“洗刷”工具開始啟動。
Code
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方法
Code
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);
}
}