明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

ASP.NET HTTP運行時組成詳細說明

[摘要]簡介  不管使用哪種底層平臺,可靠性和性能都是對所有 Web 應用程序的主要要求,盡管從某種意義上講,這兩個要求是相互矛盾的。例如,要構(gòu)建更可靠、更健壯的應用程序,可能需要將 Web 服務(wù)器與具體的應用程序分離,使應用程序在進程外工作。但是,如果在不同于 Web 服務(wù)器進程的內(nèi)存環(huán)境中工作,應用程...

簡介

  不管使用哪種底層平臺,可靠性和性能都是對所有 Web 應用程序的主要要求,盡管從某種意義上講,這兩個要求是相互矛盾的。例如,要構(gòu)建更可靠、更健壯的應用程序,可能需要將 Web 服務(wù)器與具體的應用程序分離,使應用程序在進程外工作。但是,如果在不同于 Web 服務(wù)器進程的內(nèi)存環(huán)境中工作,應用程序?qū)⒆兟R虼,需要采取合理的措施,以確保進程外代碼盡可能快地運行。

  在構(gòu)建 Microsoft? ASP.NET 運行時環(huán)境時,依據(jù)的設(shè)計原則即:充分考慮可靠性和性能。得到的 ASP.NET 進程模型包含了兩個系統(tǒng)元素 - 一個存在于 Web 服務(wù)器進程中的進程內(nèi)連接器,一個外部的輔助進程。另外,ASP.NET 運行時結(jié)構(gòu)的可伸縮能力很強,可以自動使用多處理器硬件中任意選定的處理器。這種模式被稱為“Web Garden”,它可以使多個輔助進程同時運行,而且各個進程均在獨立的處理器中。

  高度概括起來,ASP.NET 運行時具有三大屬性:

  應用程序和 ASP.NET 輔助進程之間完全分離。提供服務(wù)的輔助進程的壽命決不會影響應用程序的壽命。換句話說,當應用程序啟動并處于運行狀態(tài)時,輔助進程可以隨時終止。
盡管 ASP.NET 應用程序從不在 Web 服務(wù)器內(nèi)采用進程內(nèi)的方式運行,但大多數(shù)情況下,其總體性能仍接近于進程內(nèi)應用程序的性能。

  為 Web Garden 體系結(jié)構(gòu)提供了內(nèi)置的和可配置的支持。只要簡單檢查一下配置文件中的設(shè)置,輔助進程就可以克隆自己,以利用所有與進程密切相關(guān)的 CPU。因此,在大多數(shù)情況下,您在具備多處理器的計算機中獲得的可縮放性將呈線性增長的趨勢。(本文后面將詳細介紹此內(nèi)容。)

  本文將介紹 ASP.NET 運行時環(huán)境的組成元素,然后一步一步地講述從 URL 請求變?yōu)榧?HTML 文本的“漫長而曲折”的過程。

  除非另有說明,否則以下介紹中均指 ASP.NET 的默認進程模型,即 Microsoft? Internet Information Services (IIS) 5.x 中唯一的模型。
  ASP.NET 結(jié)構(gòu)的組件

  執(zhí)行 ASP.NET 應用程序需要宿主 Web 服務(wù)器的支持。在 Microsoft? Windows? 的 Server 平臺中,Web 服務(wù)器由名為 inetinfo.exe 的 IIS 可執(zhí)行文件表示。Windows 2000 及以上版本的操作系統(tǒng)本身均提供了 Web 服務(wù)器。但需要注意,在 Microsoft? Windows Server™ 2003 中,并未默認安裝 IIS 和 ASP.NET,必須通過單擊“控制面板”中的“添加或刪除程序”小程序?qū)⑵涮砑拥较到y(tǒng)中。

  IIS 是一個未托管的可執(zhí)行程序,它提供了一個基于 ISAPI 擴展模塊和篩選器模塊的可擴展模型。通過編寫此類模塊,開發(fā)人員可以直接管理對特定資源類型的請求,并在各個預定義的步驟中接收當前請求。擴展和篩選器是一些 DLL,可以導出一些具有已知名稱和簽名的函數(shù)。這些插件組件是在 IIS 配置數(shù)據(jù)庫中注冊并配置的。
 
  只有少數(shù)幾種被客戶端請求的資源類型由 IIS 直接處理。例如,對 HTML 頁面、文本文件、JPEG 和 GIF 圖像的傳入請求由 IIS 處理。對 Active Server Page (*.asp) 文件的請求通過調(diào)用名為 asp.dll 的 ASP 專用擴展模塊進行解析。同樣,對 ASP.NET 資源(例如,*.aspx、*.asmx、*.ashx)的請求將傳遞到 ASP.NET ISAPI 擴展。該系統(tǒng)組件是一個名為 aspnet_isapi.dll 的 Win32 DLL。ASP.NET 擴展可以處理多種資源類型,包括 Web 服務(wù)和 HTTP 處理程序調(diào)用。

  ASP.NET ISAPI 擴展是一個 Win32 DLL,未集成托管代碼。它是接收和分派對各種 ASP.NET 資源的請求的控制中心。按照設(shè)計,該模塊存在于 IIS 進程中,在具有管理員權(quán)限的 SYSTEM 帳戶下運行。開發(fā)人員和系統(tǒng)管理員不能修改此帳戶。ASP.NET ISAPI 擴展負責調(diào)用 ASP.NET 輔助進程 (aspnet_wp.exe),而該進程又負責控制請求的執(zhí)行。除了對請求進行安排以外,ASP.NET ISAPI 還監(jiān)視輔助進程的運行情況,并在性能降低到一定程度時將進程取消。

  輔助進程是一小段 Win32 shell 代碼,集成了公共語言運行庫 (CLR) 并運行托管代碼。它負責處理對 ASPX、ASMX 和 ASHX 資源的請求。一般來說,此進程在一臺給定的計算機中只有一個實例。所有當前激活的 ASP.NET 應用程序均在其中運行,每個應用程序都位于一個獨立的 AppDomain 中。但是,如前所述,輔助進程支持 Web Garden 模式,即進程的相同副本都運行在與進程密切相關(guān)的 CPU 中。(更多內(nèi)容,請參閱本文后面的“Web Garden 模型”部分。)

  ISAPI 和輔助進程之間的通訊是使用一組命名管道進行的。命名管道是一種 Win32 機制,用于跨進程邊界傳輸數(shù)據(jù)。顧名思義,命名管道的工作方式與管道相似:在一端輸入數(shù)據(jù),在另一端輸出相同的數(shù)據(jù)。建立的管道既可以連接本地進程,也可以連接遠程計算機上運行的進程。對于本地進程間通訊,管道是 Windows 中的最有效、最靈活的工具。

  為確保獲得最優(yōu)性能,aspnet_isapi 使用異步命名管道來將請求轉(zhuǎn)發(fā)給輔助進程并獲得響應。另一方面,輔助進程在需要查詢有關(guān) IIS 環(huán)境的信息(即服務(wù)器變量)時又使用同步管道。aspnet_isapi 模塊創(chuàng)建固定數(shù)量的命名管道,并使用重疊的操作以通過小的線程池處理同一時間進行的連接。當通過管道進行的數(shù)據(jù)交換操作結(jié)束后,完成例程將斷開客戶端,并重新使用管道實例為新的客戶端服務(wù)。線程池和重疊操作均可以保證使 ASP.NET ISAPI 的性能達到令人滿意的水平。但是,aspnet_isapi 擴展決不會處理 HTTP 請求。

  ASP.NET 請求的處理邏輯可以概括為以下步驟:

  當請求到達時,IIS 檢查資源類型并調(diào)用 ASP.NET ISAPI 擴展。如果啟用了默認的進程模型,aspnet_isapi 會將請求排隊,并將請求分配給輔助進程。所有的請求數(shù)據(jù)都通過異步 I/O 發(fā)送。如果啟用了 IIS 6 進程模型,請求將自動在輔助進程 (w3wp.exe) 中排隊,此輔助進程用于處理應用程序所屬的 IIS 應用程序池。IIS 6 輔助進程不了解 ASP.NET 和托管代碼的任何情況,它只是處理 *.aspx 擴展并加載 aspnet_isapi 模塊。當 ASP.NET ISAPI 在 IIS 6 進程模型中運行時,它的工作方式有所不同,僅在 w3wp.exe 輔助進程的上下文中加載 CLR。

  收到請求后,ASP.NET 輔助進程將通知 ASP.NET ISAPI,它將為請求服務(wù)。通知通過同步 I/O 實現(xiàn)。之所以使用同步模型,是因為請求只有在 ISAPI 內(nèi)部請求表中被標記為“executing”,輔助進程才能開始處理它。如果請求已經(jīng)由特殊的輔助進程進行處理,則不能再將它指定到其他進程,除非原始進程已取消。
在輔助進程的上下文中執(zhí)行請求。有時,輔助進程可能需要回調(diào) ISAPI 以完成請求,也就是需要說枚舉服務(wù)器變量。這種情況下,輔助進程將使用同步管道,因為這樣可以保持請求處理邏輯的順序。

  完成后,響應被發(fā)送到打開了異步管道的 aspnet_isapi,F(xiàn)在,請求的狀態(tài)變?yōu)椤癉one”,之后將從請求表中被刪除。如果輔助進程崩潰,正在處理的所有請求仍將保持“executing”狀態(tài)并持續(xù)一段時間。如果 aspnet_isapi 檢測到輔助進程已取消,它將自動終止請求并釋放所有相關(guān)的 IIS 資源。

  以上說明是指默認的 ASP.NET 進程模型,即在 IIS 5.x 中運行的工作模型。IIS 6(Windows Server 2003 提供)的默認工作方式對 ASP.NET 進程模型也有影響。當集成在 IIS 6.0 中時,ASP.NET 1.1 會自動調(diào)整自己的工作方式以適應宿主環(huán)境。這時,不再需要使用 aspnet_wp 輔助進程,machine.config 文件中定義的某些配置參數(shù)也被忽略。從 ASP.NET 的角度來看,IIS 6 的最大改變是有關(guān)請求的一切都在 aspnet_isapi 的控制之下,且都處在 w3wp.exe 輔助進程的上下文中。輔助進程的帳戶是為 Web 應用程序所屬的應用程序池設(shè)置的帳戶。默認情況下,該帳戶是 NETWORKSERVICE&#151,它是一個內(nèi)置的弱帳戶,在功能上與 ASPNET 等價。

  輔助進程受一個名為進程回收 (Recycling) 的功能的控制。進程回收具有 aspnet_isapi 功能,當現(xiàn)有進程消耗的內(nèi)存太多、響應太慢或掛起時可以自動啟動新進程。出現(xiàn)這種情況時,新請求將由新實例處理,新實例從而變成新的活動進程。但是,指定給舊進程的所有請求仍保持掛起狀態(tài)。如果舊進程結(jié)束了掛起的請求并進入空閑狀態(tài),該進程即終止。如果輔助進程崩潰,或者由于其他原因停止處理請求,則所有掛起的請求將被重新指定給新進程。

  盡管 ASP.NET ISAPI 和輔助進程是 ASP.NET 運行時結(jié)構(gòu)的主要組成部分,但還有其他一些可執(zhí)行文件也發(fā)揮著作用。下表列出了所有這些組件。

  表 1:構(gòu)成 ASP.NET 運行時環(huán)境的可執(zhí)行文件

名稱類型帳戶
aspnet_isapi.dllWin32 DLL(ISAPI 擴展)LOCAL SYSTEM
aspnet_wp.exeWin32EXE ASPNET
aspnet_filter.dllWin32 DLL(ISAPI 篩選器)LOCAL SYSTEM
aspnet_state.exeWin32 NTService ASPNET

  aspnet_filter.dll 組件是一個小的 Win32 ISAPI 篩選器,用來備份 ASP.NET 應用程序的無 Cookie 會話狀態(tài)。在 Windows Server 2003 中,當啟用 IIS 6 進程模型時,aspnet_filter.dll 還將篩選出 Bin 目錄中對非可執(zhí)行資源的請求。

  aspnet_state.exe 的作用對 Web 應用程序更為重要,因為它用于管理會話狀態(tài)。該項服務(wù)是可選的,可以用來在 Web 應用程序內(nèi)存空間之外保存會話狀態(tài)數(shù)據(jù)。該可執(zhí)行文件是一種 NT 服務(wù),既可以在本地運行,也可以遠程運行。當該服務(wù)被激活后,可以將 ASP.NET 應用程序配置為將所有會話信息保存在此進程的內(nèi)存中。一種類似的方案是提供更為可靠的數(shù)據(jù)存儲方式,不受進程回收和 ASP.NET 應用程序故障的影響。該服務(wù)在 ASPNET 本地帳戶下運行,但可以使用服務(wù)控制管理器 (Service Control Manager) 接口來配置它。

  另一個應該介紹的可執(zhí)行文件是 aspnet_regiis.exe,盡管嚴格來講,它并不屬于 ASP.NET 運行時結(jié)構(gòu)。該實用程序可以用來配置環(huán)境,以在一臺計算機上并行執(zhí)行不同版本的 ASP.NET,還可用于維修 IIS 和 ASP.NET 損壞的配置。該實用程序的工作方式是更新存儲在 IIS 配置數(shù)據(jù)庫的根目錄和子目錄中的腳本映射。腳本映射是資源類型和 ASP.NET 模塊之間的一種關(guān)聯(lián)關(guān)系。最后,還可以使用該工具來顯示已安裝的 ASP.NET 版本的狀態(tài),執(zhí)行其他配置操作,如授予對特定文件夾的 NTFS 權(quán)限、創(chuàng)建客戶腳本目錄。

  Web Garden 模型

  Web Garden 模型可以通過 machine.config 文件中的 <processModel> 部分進行配置。請注意,<processModel> 部分是唯一不能放在應用程序特定的 web.config 文件中的配置部分。這就是說,Web Garden 模式可以應用到計算機中運行的所有應用程序。但通過使用 machine.config 源文件中的 <location> 節(jié)點,可以針對各個應用程序調(diào)節(jié)計算機的設(shè)置。

 。紁rocessModel> 部分有兩個屬性可以影響 Web Garden 模型,它們是 webGarden 和 cpuMask。webGarden 屬性接受布爾值,表示是否使用了多個輔助進程(一個相關(guān)的 CPU 對應一個進程)。默認情況下,該屬性的值為 false。cpuMask 屬性保存一個 DWORD 值,該值的二進制表示為能夠運行 ASP.NET 輔助進程的 CPU 提供了位屏蔽。其默認值為 -1 (0xFFFFFF),表示可以使用所有可用的 CPU。如果 webGarden 屬性為 false,則 cpuMask 屬性的內(nèi)容將被忽略。cpuMask 屬性還為正在運行的 aspnet_wp.exe 的副本數(shù)設(shè)置了上限。

  常言道“閃光的不都是金子”,用在這里很合適。Web Garden 模式使得多個輔助進程可以同時運行。但是,需要注意的是所有進程都會有自己的應用程序狀態(tài)、進程內(nèi)會話狀態(tài)、ASP.NET 緩存、靜態(tài)數(shù)據(jù)以及運行應用程序所需的其他內(nèi)容。啟用 Web Garden 模式之后,ASP.NET ISAPI 將根據(jù) CPU 的數(shù)量盡可能多地啟動輔助進程,每個輔助進程都是下一進程的完整克。恳贿M程都與相應的 CPU 密切相關(guān))。為平衡工作負荷,傳入的請求以單循環(huán)的方式在運行的進程之間進行劃分。輔助進程就象在單處理器中一樣被回收。請注意,ASP.NET 繼承了操作系統(tǒng)中所有的 CPU 使用限制,并且不包括實現(xiàn)限制的自定義語義。

  總之,Web Garden 模型并不適用于所有應用程序。應用程序的狀態(tài)越多,其的性能損失也越多。工作數(shù)據(jù)存儲在共享內(nèi)存的塊中,以便一個進程輸入的變化可以立即被其他進程得知。但是,處理請求時,工作數(shù)據(jù)被復制到進程的上下文中。因此,各個輔助進程將處理自己的工作數(shù)據(jù),而應用程序的狀態(tài)越多,性能損失就越大。鑒于此,仔細、明智的應用程序基準測試是絕對必要的。

  只有重啟 IIS 后,對配置文件中 <processModel> 部分所做的更改才會生效。在 IIS 6 中,Web Garden 模式的參數(shù)保存在 IIS 配置數(shù)據(jù)庫中,webGarden 和 cpuMask 屬性被忽略。

  HTTP 管道

  ASP.NET ISAPI 擴展啟動輔助進程后,它將傳遞部分命令行參數(shù)。輔助進程使用這些參數(shù)來執(zhí)行加載 CLR 前需要執(zhí)行的任務(wù)。傳遞的值包括:COM 和 DCOM 安全性所要求的身份驗證等級、可以使用的命名管道的數(shù)量和 IIS 進程標識。命名管道的名稱是使用 IIS 進程標識和允許的管道數(shù)隨機生成的。輔助進程不接收可用管道的名稱,但可以接收識別管道名稱所需的信息。

  COM 和 DCOM 安全性與 Microsoft? .NET Framework 有何關(guān)系?實際上,CLR 是作為 COM 對象提供的。更準確地說,CLR 本身不是由 COM 代碼構(gòu)成的,但是指向 CLR 的接口卻是一個 COM 對象。因此,輔助進程加載 CLR 的方式與加載 COM 對象的方式相同。

  當 ASPX 請求遇到 IIS 時,Web 服務(wù)器將根據(jù)選擇的身份驗證模型(匿名、Windows、Basic 或 Digest)來分配一個令牌。當輔助進程收到要處理的請求時,令牌被傳遞到輔助進程。請求由輔助進程中的線程獲取。該線程從最初獲取傳入請求的 IIS 線程繼承身份令牌。在 aspnet_wp.exe 中,負責處理請求的實際帳戶取決于在特殊的 ASP.NET 應用程序中是如何配置模擬的。如果模擬被禁用(默認設(shè)置),則線程將在輔助進程的帳戶下運行。默認情況下,該帳戶在 ASP.NET 進程模型中為 ASPNET,在 IIS 6 進程模型中為 NETWORKSERVICE。這兩個帳戶都是“弱”帳戶,提供的功能比較有限,可以有效抵擋回復性攻擊 (Revert-to-self Attack)。(回復性攻擊是指將模擬的客戶端的安全性令牌回復到父進程令牌。為輔助進程分配弱帳戶可以挫敗此類攻擊。)

  高度概括起來,ASP.NET 輔助進程完成的一項主要任務(wù)就是將請求交給一系列稱為的 HTTP 管道的托管對象。要激活 HTTP 管道,可以創(chuàng)建一個 HttpRuntime 類的新實例,然后調(diào)用其 ProcessRequest 方法。如前所述,ASP.NET 中始終只運行一個輔助進程(除非啟用了 Web Garden 模型),該進程在獨立的 AppDomain 中管理所有的 Web 應用程序。每個 AppDomain 都有自己的 HttpRuntime 類實例,即管道中的輸入點。HttpRuntime 對象初始化一系列有助于實現(xiàn)請求的內(nèi)部對象。Helper 對象包括緩存管理器(Cache 對象)和內(nèi)部文件系統(tǒng)監(jiān)視器(用于檢測構(gòu)成應用程序的源文件的更改)。HttpRuntime 為請求創(chuàng)建上下文,并用與請求相關(guān)的 HTTP 信息填充上下文。上下文用 HttpContext 類的實例來表示。

  另一個在 HTTP 運行時的設(shè)置初期創(chuàng)建的 Helper 對象是文本書寫器,用于包含瀏覽器的響應文本。文本書寫器是 HttpWriter 類的實例,此對象對頁面代碼以編程方式發(fā)送的文本進行緩存。HTTP 運行時被初始化后,它將查找實現(xiàn)請求的應用程序?qū)ο。應用程序(qū)ο笫?HttpApplication 類的實例,該類就是 global.asax 文件背后的類。global.asax 在編程時是可選的,但在構(gòu)建結(jié)構(gòu)時是必需的。因此,如果應用程序中沒有構(gòu)建類,則必須使用默認對象。ASP.NET 運行時包括幾個中間工廠類,可以用來查找并返回有效的 Handler 對象以處理請求。整個過程中用到的第一個工廠類是 HttpApplicationFactory。它的主要任務(wù)是使用 URL 信息來查找 URL 虛擬目錄和匯集的 HttpApplication 對象之間的匹配關(guān)系。

  應用程序工廠類的行為可以概括為以下幾點:

  工廠類維護 HttpApplication 對象池,并使用它們來處理應用程序的請求。池的壽命與應用程序的壽命相同。

  應用程序的第一個請求到達時,工廠類提取有關(guān)應用程序類型的信息(global.asax 類)、設(shè)置用于監(jiān)視更改的文件、創(chuàng)建應用程序狀態(tài)并觸發(fā) Application_OnStart 事件。

  工廠類從池中獲取一個 HttpApplication 實例,并將要處理的請求放入實例中。如果沒有可用的對象,則創(chuàng)建一個新的 HttpApplication 對象。要創(chuàng)建 HttpApplication 對象,需要先完成 global.asax 應用程序文件的編譯。

  HttpApplication 開始處理請求,并且只能在完成這個請求后才能處理新的請求。如果收到來自同一資源的新請求,則由池中的其他對象來處理。

  應用程序?qū)ο笤试S所有注冊的 HTTP 模塊對請求進行預處理,并找出最適合處理請求的處理程序類型。這通過查找請求的 URL 的擴展和配置文件中的信息來完成。

  HTTP 處理程序是一些實現(xiàn) IHttpHandler 接口的類。.NET Framework 為常見的資源類型提供了一些預定義的處理程序,包括 ASPX 頁面和 Web 服務(wù)。machine.config 文件中的 <httpHandlers> 部分定義了 HttpApplication 對象必須實例化才能處理特定類型資源的請求的類名。如果 Helper 類是一個處理程序工廠,GetHandler 方法將確定要使用的處理程序類型。這時,將從一組類似的對象中獲取適當類型的處理程序,并對其進行配置以處理請求。

  IHttpHandler 接口提供了兩個方法:IsReusable 和 ProcessRequest。前者將返回一個布爾值,表示處理程序是否可以被匯集。(大多數(shù)預定義的處理程序都是匯集的,但是您可以自行定義每次都需要新實例的處理程序。)ProcessRequest 方法包含處理特定類型資源所需的所有邏輯。例如,ASPX 頁面的處理程序基于以下偽代碼:

private void ProcessRequest()
{
// 確定請求是否是回發(fā) (postback)
IsPostBack = DeterminePostBackMode();

// 觸發(fā) ASPX 源代碼的 Page_Init 事件
PageInit();

// 加載 ViewState,處理已發(fā)送的值。
if (IsPostBack) {
LoadPageViewState();
ProcessPostData();
}

// 觸發(fā) ASPX 源代碼的 Page_Load 事件
PageLoad();

// 1) 再次處理已發(fā)送的值(當
// 動態(tài)創(chuàng)建控件時)
// 2) 將屬性更改的服務(wù)器端事件提升為輸入驅(qū)動的
// 控件(即復選框的狀態(tài)改變)
// 3) 執(zhí)行與回發(fā)事件相關(guān)的所有代碼
if (IsPostBack) {
ProcessPostDataSecondTry();
RaiseChangedEvents();
RaisePostBackEvent();
}

// 觸發(fā) ASPX 源代碼的 Page_PreRender 事件
PreRender();

// 將控件的當前狀態(tài)保存到 ViewState 中
SavePageViewState();

// 將頁面內(nèi)容呈現(xiàn)給 HTML
RenderControl(CreateHtmlTextWriter(Response.Output));
}

  無論調(diào)用的資源類型如何,基于 HTTP 處理程序的模型是相同的。唯一隨資源類型變化而變化的元素是處理程序。HttpApplication 對象負責查找應該使用哪種處理程序來處理請求。HttpApplication 對象還負責檢測對動態(tài)創(chuàng)建的、表示資源的程序集(如 .aspx 頁面或 .asmx Web 服務(wù))所進行的更改。如果檢測到更改,應用程序?qū)ο髮⒋_保編譯并加載所請求的資源的最新來源。

  臨時文件和頁面程序集

  要全面了解 ASP.NET HTTP 運行時,讓我們來分析一下當請求 ASP.NET 頁面時,文件系統(tǒng)層所發(fā)生的變化。接下來,您將了解由 HTTP 管道的對象管理和監(jiān)視的一組動態(tài)創(chuàng)建的臨時文件。

  雖然可以將頁面的核心代碼隔離在代碼背后的 C# 或 Microsoft? Visual Basic? .NET 類中,但可以將 Web 頁面編寫和部署為 .aspx 文本文件。對于要顯示為 URL 的頁面來說,.aspx 文件在應用程序的 Web 空間中必須始終可用。.aspx 文件的實際內(nèi)容將確定應用程序?qū)ο笠虞d的程序集(或多個程序集)。

  按照設(shè)計,HttpApplication 對象將查找一個根據(jù)請求的 ASPX 文件命名的類。如果頁面命名為 sample.aspx,則要加載的相應的類名為 ASP.sample_aspx。應用程序?qū)ο笤?Web 應用程序的所有程序集文件夾中查找這樣的類,這些文件夾包括全局程序集緩存 (GAC)、Bin 子文件夾和 Temporary ASP.NET Files 文件夾。如果未找到這樣的類,HTTP 結(jié)構(gòu)將分析 .aspx 文件的源代碼,創(chuàng)建一個 C# 或 Visual Basic .NET 類(具體創(chuàng)建哪種類,取決于 .aspx 頁面上設(shè)置的語言),同時對其進行編譯。新創(chuàng)建的程序集的名稱是隨機生成的,位于特定于應用程序的子文件夾中,路徑如下所示: C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files。

  子文件夾 v1.1.4322 特定于 ASP.NET 1.1。如果您使用的是 ASP.NET 1.0,子文件夾的版本號會有所不同,即子文件夾名為 v1.0.3705。再次訪問頁面時,程序集就已存在,不需要重新創(chuàng)建。但是,HttpApplication 對象是如何確定特定于頁面的程序集是否存在呢?它每次都要掃描大量文件夾嗎?不,并不是這樣。

  應用程序?qū)ο笾徊榭?Temporary ASP.NET Files 文件夾中某個特殊文件夾的內(nèi)容。具體路徑(特定于應用程序的路徑)由 HttpRuntime.CodegenDir 屬性返回。如果是第一次訪問 .aspx 文件(即還未創(chuàng)建頁面程序集),則該文件夾中就不存在以 ASPX 頁面名稱開頭的 XML 文件。例如,具有動態(tài)程序集的 sample.aspx 頁面應有如下的條目:

  sample.aspx.XXXXX.xml

  XXXXX 占位符是一種散列代碼。通過讀取該 XML 文件的內(nèi)容,應用程序?qū)ο缶涂梢粤私庖虞d的程序集的名稱以及要在其中獲取的類。以下代碼片段是這種 Helper 文件的典型內(nèi)容。包含 ASP.sample_aspx 類的程序集的名稱是 mvxvx8xr。

<preserve assem="mvxvx8xr" type="ASP.sample_aspx">
<filedep name="c:\inetpub\wwwroot\vdir\sample.aspx" />
</preserve>

  當然,只有在分析 filedep 文件的源代碼以生成動態(tài)程序集時才創(chuàng)建該文件。對 filedep 文件所做的任何更改都會使程序集無效,在下一次請求時必須重新編譯。需要注意的是,在 ASP.NET 架構(gòu)的未來版本中,該實現(xiàn)過程可能會有較大改變。不論什么原因,只要您決定在當前應用程序中使用它,都必須十分小心。

  由于更新而要為頁面創(chuàng)建新的程序集時,ASP.NET 將驗證是否可以刪除舊的程序集。如果舊的程序集只包含修改后的頁面的類,ASP.NET 將試圖刪除并替換該程序集,否則將在保留舊程序集的情況下創(chuàng)建一個新程序集。

  在刪除過程中,ASP.NET 可能會發(fā)現(xiàn)程序集文件已被加載并鎖定。這種情況下,可以為舊程序集添加一個“.DELETE”擴展名,以將其重新命名。(注意,所有 Windows 文件都可以在使用過程中重新命名。)只要應用程序重新啟動(例如,由于對某個應用程序文件如 global.asax 和 web.config 進行了更改),這些臨時的 .DELETE 文件就將被刪除。但在處理下一個請求時,ASP.NET 運行時不會刪除這些文件。

  請注意,默認情況下,在整個應用程序重新啟動之前,每個 ASP.NET 應用程序最多可以重新編譯 15 個頁面,同時會損失一些會話和應用程序數(shù)據(jù)。當最近的編譯次數(shù)超過了 <httpRuntime> 部分的 numRecompilesBeforeAppRestart 屬性中設(shè)置的閾值時,將卸載 AppDomain,并重新啟動應用程序。還要注意,在 .NET Framework 中,您無法卸載單個程序集。AppDomain 是可以從 CLR 卸載的最小的代碼塊。

  小結(jié)

  ASP.NET 應用程序有兩大特征:進程模型和頁面對象模型。ASP.NET 提前使用了 IIS 6.0 的一些功能,而 IIS 6.0 則是 Windows Server 2003 中提供的全新的、開創(chuàng)性的 Microsoft Web 信息服務(wù)。尤其值得一提的是,在獨立的輔助進程中運行的 ASP.NET 應用程序,其行為與 IIS 6 中的所有應用程序相同。而且,盡管會出現(xiàn)運行時異常、內(nèi)存泄露或程序錯誤,ASP.NET 運行時仍能自動回收輔助進程以保證實現(xiàn)卓越的性能。這種功能已成為 IIS 6.0 的系統(tǒng)功能。

  在本文中,我概括介紹了默認的 ASP.NET 進程模型的基礎(chǔ)知識,以及 IIS 級代碼(ASP.NET ISAPI 擴展)和輔助進程之間的交互。同時,還介紹了與 IIS 6 進程模型之間的最新區(qū)別。