關于ASP.NET與CLR相互關系的一些總結
CLR(COM服務器)
CLR作為一個COM服務器實現在MSCorWks.dll文件中。安裝.NET Framework時,表示CLR的COM服務器被注冊到Windows的注冊表里。
MSCorEE.dll(墊片)
MSCorEE.dll的職責是判斷創建何種版本的CLR。 非托管應用程序宿主調用MSCorEE.dll(shim)中CorBindToRuntimeEx函數或者另一個相似的函數來創建CLR COM的實例。
一臺機器可以安裝多個版本的CLR,但在機器中只有一個版本的MSCorEE.dll文件。以上兩者之間的關系如下代碼所示(c++):MSCorEE.dll(墊片)---->CLR(COM服務器)
#include <MSCorEE.h>
#include <stdio.h>
#pragma comment(lib,"mscoree.lib")
int main(int argc, CHAR* argv[])
{
ICLRRuntimeHost *pClrHost;
//調用<MSCorEE.h>中的CorBindToRuntimeEx()生成COM服務器
HRESULT hr= CorBindToRuntimeEx(NULL, NULL, NULL, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pClrHost);
//啟動clr
pClrHost->Start();
//............................其他操作
//終止clr
pClrHost->Stop();
getchar();
return 0;
}
應用程序域(AppDomain)
一個應用程序域是一組程序集的一個容器。應用程序域的全部目的就是提供隔離性。
上圖為一個單獨的Windows進程,該進程中運行著一個CLR COM服務器。該CLR中每個應用程序域都有自己的加載器堆。(系統域,共享域,默認域#1,其他域#2)
一些特殊的程序集如MSCorLib.dll,它需要被所有的應用程序域共享,那么他就以一種對應用程序域保持中立的方式被加載,由CLR維護一個特殊的加載器堆。
線程與應用程序域的關系
線程與應用程序域沒有一對一的關系。多個應用程序域可以位于一個Windows進程中,所以一個線程可以執行一個應用程序域中的代碼,然后又執行另一個應用程序域中的代碼。從CLR的角度看,線程每次只能執行一個應用程序域中的代碼。線程可以通過Thead的靜態方法GetDomain來請求CLR當前正在那個應用程序域中執行。
關于卸載的問題
一旦CLR加載到Windows的進程,就永遠不會被卸載,要想卸載進程中的CLR,只能終止進程,導致Windows清理該進程使用的所有資源。
共享域的程序集永遠不會被卸載,回收它們的唯一方式就是終止Windows進程。
卸載一個應用程序域(默認域#1,其他域#2)可以導致CLR卸載應用程序域中的所有程序集,并且釋放應用程序域的加載器堆。
ASP.NET 應用程序
ASP.NET是一個ISAPI DLL(實現于ASPNET_ISAPI.DLL中)。
①當客戶端請求一個由ASP.NET ISAPI DLL處理的URL時(第一次),ASP.NET會創建一個工作進程(ASPNET_wp.exe / w3wp.exe即宿主,工作進程是一個寄宿有CLR COM服務器的Windows進程)。
②CLR為該Web程序創建一個新的應用程序域。(參考上面的圖)
③CLR將必要的程序集加載到新建的應用程序域中。
④CLR創建一個Web應用程序類型的實例,調用其中方法響應客戶端請求。隨著Web應用程序的運行,如果代碼中引用到了更多類型,CLR會繼續將必要的程序集加載到當前Web應用程序的應用程序域中。
當更多的客戶端向一個已經運行的Web應用程序發出請求時,ASP.NET不會再去創建新的應用程序域,相反,它會使用現有的應用程序域,創建一個新的Web應用程序類型的實例,并調用其中的方法。這些方法被JIT編譯成了本地代碼,所以后續客戶端的請求處理性能將會有所提高。
看下我們的工作進程,如下任務管理器截圖中所示:
ASP.NET 應用程序生命周期的各個階段
(一)用戶從 Web 服務器請求應用程序資源(映射文件擴展名)
ASP.NET 應用程序的生命周期以瀏覽器向 Web 服務器發送請求為起點。ASP.NET 是 Web 服務器下的 ISAPI 擴展。Web 服務器接收到請求時,會對所請求的文件的文件擴展名進行檢查,確定應由哪個 ISAPI 擴展處理該請求,然后將該請求傳遞給合適的 ISAPI 擴展。ASP.NET 處理已映射到其上的文件擴展名,如 .aspx、.ascx、.ashx 和 .asmx。
(二)ASP.NET 接收對應用程序的第一個請求。
當 ASP.NET 接收到對應用程序中任何資源的第一個請求時,名為 ApplicationManager 的類會(1)創建一個應用程序域。在應用程序域中,(2)將HostingEnvironment 類創建一個實例,該實例提供對有關應用程序的信息(如存儲該應用程序的文件夾的名稱)的訪問。下面的關系圖說明了這種關系:
運行ASP.NET的進程為W3WP.EXE。
編寫下述代碼,我們可以觀察一下HostingEnvironment 的各種屬性:
2 protected void Page_Load(object sender, EventArgs e)
3 {
4 StringBuilder sb = new StringBuilder();
5 sb.Append(System.Web.Hosting.HostingEnvironment.ApplicationID).Append("<br/>")
6 .Append(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath).Append("<br/>")
7 .Append(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath).Append("<br/>")
8 .Append(System.Web.Hosting.HostingEnvironment.SiteName).Append("<br/>")
9 .Append(System.Web.Hosting.HostingEnvironment.ApplicationHost.ToString());
10 Response.Write(sb.ToString());
11 }
12 </script>
輸出內容為:
E:\MVC\Jasen\Jasen.Web\ //存儲該應用程序的文件夾的名稱
/
默認網站
System.Web.Hosting.SimpleApplicationHost
(三)為每個請求創建 ASP.NET 核心對象。
ASP.NET 創建并初始化核心對象,如 HttpContext、HttpRequest 和 HttpResponse。HttpContext 類包含特定于當前應用程序請求的對象,如 HttpRequest 和 HttpResponse 對象。HttpRequest 對象包含有關當前請求的信息,包括 Cookie 和瀏覽器信息。HttpResponse 對象包含發送到客戶端的響應,包括所有呈現的輸出和 Cookie。
(四)將 HttpApplication 對象分配給請求
初始化所有核心應用程序對象之后,將通過創建 HttpApplication 類的實例啟動應用程序。如果應用程序具有 Global.asax 文件,則 ASP.NET 會創建 Global.asax 類的一個實例,并使用該派生類表示應用程序。MVC Global.asax文件內容如下:
2 {
3 protected void Application_Start()
4 {
//RegisterGlobalFilters(GlobalFilters.Filters);
//ViewEngines.Engines.Add(new ViewEngine());
5 //請求 ASP.NET 應用程序中第一個資源時調用。在應用程序的生命周期期間僅調用一次
6 //Application_Start 方法。可以使用此方法執行啟動任務,如將數據加載到緩存中以及初始化靜態值。
7
8 //在應用程序啟動期間應僅設置靜態數據。
9 }
10
11 public override void Init()
12 {
13 base.Init();//在創建了所有模塊之后,對 HttpApplication 類的每個實例都調用一次。
14 }
15
16 public override void Dispose()
17 {
18 base.Dispose();//在銷毀應用程序實例之前調用。可使用此方法手動釋放任何非托管資源。
19 }
20
21 public void Application_End()
22 {
23 //在卸載應用程序之前對每個應用程序生命周期調用一次。
24 }
25 }
HttpApplication 進程的一個實例每次只處理一個請求。Application_Start 和 Application_End 方法,在應用程序域的生命周期期間,ASP.NET 僅調用這些方法一次,而不是對每個 HttpApplication 實例都調用一次。
(五)由 HttpApplication 管線處理請求。在處理該請求時將由 HttpApplication 類執行以下事件。
1.對請求進行驗證,將檢查瀏覽器發送的信息,并確定其是否包含潛在惡意標記。
2.如果已在 Web.config 文件的 UrlMappingsSection 節中配置了任何 URL,則執行 URL 映射。
3.引發 BeginRequest 事件。
4.引發 AuthenticateRequest 事件。引發 PostAuthenticateRequest 事件。
5.引發 AuthorizeRequest 事件。引發 PostAuthorizeRequest 事件。
6.引發 ResolveRequestCache 事件。引發 PostResolveRequestCache 事件。
7.根據所請求資源的文件擴展名(在應用程序的配置文件中映射),選擇實現 IHttpHandler 的類,對請求進行處理。如果該請求針對從 Page 類派生的對象(頁),并且需要對該頁進行編譯,則 ASP.NET 會在創建該頁的實例之前對其進行編譯。
8.引發 PostMapRequestHandler 事件。
9.引發 AcquireRequestState 事件。引發 PostAcquireRequestState 事件。
10.引發 PreRequestHandlerExecute 事件。
11.為該請求調用合適的 IHttpHandler 類的 ProcessRequest 方法。例如,如果該請求針對某頁,則當前的頁實例將處理該請求。一般處理文件ashx的ProcessRequest():速度較快
12.引發 PostRequestHandlerExecute 事件。
13.引發 ReleaseRequestState 事件。引發 PostReleaseRequestState 事件。
14.如果定義了 Filter 屬性,則執行響應篩選。
15.引發 UpdateRequestCache 事件。引發 PostUpdateRequestCache 事件。
16.引發 EndRequest 事件。
17.引發 PreSendRequestHeaders 事件。
18.引發 PreSendRequestContent 事件。
2年多了,回過來再重新溫習一次,感覺不錯。