ASP.NET HTTP 運行時 一個請求從 URL 字符串到 HTML 代碼的“漫長曲折”之路 Dino Esposito Wintellect 2003年7月10日 摘要:本文詳細介紹了 HTTP 運行時的組成部分,以及在處理對 ASP.NET 應用程序的各種請求時采用的邏輯。文章還以 Web Garden 模型和最新的 IIS 6 進程模型為切入點,分析了輔助進程的行為,并說明了 HTTP 請求變為純 HTML 文本的全過程。(本文包含一些指向英文站點的鏈接。)
適用于: Microsoft? ASP.NET
目錄 簡介 ASP.NET 結構的組件 Web Garden 模型 HTTP 管道 臨時文件和頁面程序集 小結 簡介 不管使用哪種底層平臺,可靠性和性能都是對所有 Web 應用程序的主要要求,盡管從某種意義上講,這兩個要求是相互矛盾的。例如,要構建更可靠、更健壯的應用程序,可能需要將 Web 服務器與具體的應用程序分離,使應用程序在進程外工作。但是,如果在不同于 Web 服務器進程的內存環境中工作,應用程序將變慢。因此,需要采取合理的措施,以確保進程外代碼盡可能快地運行。
在構建 Microsoft? ASP.NET 運行時環境時,依據的設計原則即:充分考慮可靠性和性能。得到的 ASP.NET 進程模型包含了兩個系統元素 - 一個存在于 Web 服務器進程中的進程內連接器,一個外部的輔助進程。另外,ASP.NET 運行時結構的可伸縮能力很強,可以自動使用多處理器硬件中任意選定的處理器。這種模式被稱為“Web Garden”,它可以使多個輔助進程同時運行,而且各個進程均在獨立的處理器中。
高度概括起來,ASP.NET 運行時具有三大屬性:
應用程序和 ASP.NET 輔助進程之間完全分離。提供服務的輔助進程的壽命決不會影響應用程序的壽命。換句話說,當應用程序啟動并處于運行狀態時,輔助進程可以隨時終止。 盡管 ASP.NET 應用程序從不在 Web 服務器內采用進程內的方式運行,但大多數情況下,其總體性能仍接近于進程內應用程序的性能。 為 Web Garden 體系結構提供了內置的和可配置的支持。只要簡單檢查一下配置文件中的設置,輔助進程就可以克隆自己,以利用所有與進程密切相關的 CPU。因此,在大多數情況下,您在具備多處理器的計算機中獲得的可縮放性將呈線性增長的趨勢。(本文后面將詳細介紹此內容。) 本文將介紹 ASP.NET 運行時環境的組成元素,然后一步一步地講述從 URL 請求變為純 HTML 文本的“漫長而曲折”的過程。
除非另有說明,否則以下介紹中均指 ASP.NET 的默認進程模型,即 Microsoft? Internet Information Services (IIS) 5.x 中唯一的模型。
ASP.NET 結構的組件 執行 ASP.NET 應用程序需要宿主 Web 服務器的支持。在 Microsoft? Windows? 的 Server 平臺中,Web 服務器由名為 inetinfo.exe 的 IIS 可執行文件表示。Windows 2000 及以上版本的操作系統本身均提供了 Web 服務器。但需要注意,在 Microsoft? Windows Server? 2003 中,并未默認安裝 IIS 和 ASP.NET,必須通過單擊“控制面板”中的“添加或刪除程序”小程序將其添加到系統中。
只有少數幾種被客戶端請求的資源類型由 IIS 直接處理。例如,對 HTML 頁面、文本文件、JPEG 和 GIF 圖像的傳入請求由 IIS 處理。對 Active Server Page (*.asp) 文件的請求通過調用名為 asp.dll 的 ASP 專用擴展模塊進行解析。同樣,對 ASP.NET 資源(例如,*.aspx、*.asmx、*.ashx)的請求將傳遞到 ASP.NET ISAPI 擴展。該系統組件是一個名為 aspnet_isapi.dll 的 Win32 DLL。ASP.NET 擴展可以處理多種資源類型,包括 Web 服務和 HTTP 處理程序調用。
ASP.NET ISAPI 擴展是一個 Win32 DLL,未集成托管代碼。它是接收和分派對各種 ASP.NET 資源的請求的控制中心。按照設計,該模塊存在于 IIS 進程中,在具有管理員權限的 SYSTEM 帳戶下運行。開發人員和系統管理員不能修改此帳戶。ASP.NET ISAPI 擴展負責調用 ASP.NET 輔助進程 (aspnet_wp.exe),而該進程又負責控制請求的執行。除了對請求進行安排以外,ASP.NET ISAPI 還監視輔助進程的運行情況,并在性能降低到一定程度時將進程取消。
輔助進程是一小段 Win32 shell 代碼,集成了公共語言運行庫 (CLR) 并運行托管代碼。它負責處理對 ASPX、ASMX 和 ASHX 資源的請求。一般來說,此進程在一臺給定的計算機中只有一個實例。所有當前激活的 ASP.NET 應用程序均在其中運行,每個應用程序都位于一個獨立的 AppDomain 中。但是,如前所述,輔助進程支持 Web Garden 模式,即進程的相同副本都運行在與進程密切相關的 CPU 中。(更多內容,請參閱本文后面的“Web Garden 模型”部分。)
ISAPI 和輔助進程之間的通訊是使用一組命名管道進行的。命名管道是一種 Win32 機制,用于跨進程邊界傳輸數據。顧名思義,命名管道的工作方式與管道相似:在一端輸入數據,在另一端輸出相同的數據。建立的管道既可以連接本地進程,也可以連接遠程計算機上運行的進程。對于本地進程間通訊,管道是 Windows 中的最有效、最靈活的工具。
盡管 ASP.NET ISAPI 和輔助進程是 ASP.NET 運行時結構的主要組成部分,但還有其他一些可執行文件也發揮著作用。下表列出了所有這些組件。
表 1:構成 ASP.NET 運行時環境的可執行文件
名稱 類型 帳戶 aspnet_isapi.dll Win32 DLL(ISAPI 擴展) LOCAL SYSTEM aspnet_wp.exe Win32 EXE ASPNET aspnet_filter.dll Win32 DLL(ISAPI 篩選器) LOCAL SYSTEM aspnet_state.exe Win32 NT Service ASPNET
aspnet_filter.dll 組件是一個小的 Win32 ISAPI 篩選器,用來備份 ASP.NET 應用程序的無 Cookie 會話狀態。在 Windows Server 2003 中,當啟用 IIS 6 進程模型時,aspnet_filter.dll 還將篩選出 Bin 目錄中對非可執行資源的請求。
aspnet_state.exe 的作用對 Web 應用程序更為重要,因為它用于管理會話狀態。該項服務是可選的,可以用來在 Web 應用程序內存空間之外保存會話狀態數據。該可執行文件是一種 NT 服務,既可以在本地運行,也可以遠程運行。當該服務被激活后,可以將 ASP.NET 應用程序配置為將所有會話信息保存在此進程的內存中。一種類似的方案是提供更為可靠的數據存儲方式,不受進程回收和 ASP.NET 應用程序故障的影響。該服務在 ASPNET 本地帳戶下運行,但可以使用服務控制管理器 (Service Control Manager) 接口來配置它。
另一個應該介紹的可執行文件是 aspnet_regiis.exe,盡管嚴格來講,它并不屬于 ASP.NET 運行時結構。該實用程序可以用來配置環境,以在一臺計算機上并行執行不同版本的 ASP.NET,還可用于維修 IIS 和 ASP.NET 損壞的配置。該實用程序的工作方式是更新存儲在 IIS 配置數據庫的根目錄和子目錄中的腳本映射。腳本映射是資源類型和 ASP.NET 模塊之間的一種關聯關系。最后,還可以使用該工具來顯示已安裝的 ASP.NET 版本的狀態,執行其他配置操作,如授予對特定文件夾的 NTFS 權限、創建客戶腳本目錄。
Web Garden 模型 Web Garden 模型可以通過 machine.config 文件中的 <processModel> 部分進行配置。請注意,<processModel> 部分是唯一不能放在應用程序特定的 web.config 文件中的配置部分。這就是說,Web Garden 模式可以應用到計算機中運行的所有應用程序。但通過使用 machine.config 源文件中的 <location> 節點,可以針對各個應用程序調節計算機的設置。
<processModel> 部分有兩個屬性可以影響 Web Garden 模型,它們是 webGarden 和 cpuMask。webGarden 屬性接受布爾值,表示是否使用了多個輔助進程(一個相關的 CPU 對應一個進程)。默認情況下,該屬性的值為 false。cpuMask 屬性保存一個 DWORD 值,該值的二進制表示為能夠運行 ASP.NET 輔助進程的 CPU 提供了位屏蔽。其默認值為 -1 (0xFFFFFF),表示可以使用所有可用的 CPU。如果 webGarden 屬性為 false,則 cpuMask 屬性的內容將被忽略。cpuMask 屬性還為正在運行的 aspnet_wp.exe 的副本數設置了上限。
常言道“閃光的不都是金子”,用在這里很合適。Web Garden 模式使得多個輔助進程可以同時運行。但是,需要注意的是所有進程都會有自己的應用程序狀態、進程內會話狀態、ASP.NET 緩存、靜態數據以及運行應用程序所需的其他內容。啟用 Web Garden 模式之后,ASP.NET ISAPI 將根據 CPU 的數量盡可能多地啟動輔助進程,每個輔助進程都是下一進程的完整克隆(每一進程都與相應的 CPU 密切相關)。為平衡工作負荷,傳入的請求以單循環的方式在運行的進程之間進行劃分。輔助進程就象在單處理器中一樣被回收。請注意,ASP.NET 繼承了操作系統中所有的 CPU 使用限制,并且不包括實現限制的自定義語義。
COM 和 DCOM 安全性與 Microsoft? .NET Framework 有何關系?實際上,CLR 是作為 COM 對象提供的。更準確地說,CLR 本身不是由 COM 代碼構成的,但是指向 CLR 的接口卻是一個 COM 對象。因此,輔助進程加載 CLR 的方式與加載 COM 對象的方式相同。
// 將頁面內容呈現給 HTML RenderControl(CreateHtmlTextWriter(Response.Output)); }
無論調用的資源類型如何,基于 HTTP 處理程序的模型是相同的。唯一隨資源類型變化而變化的元素是處理程序。HttpApplication 對象負責查找應該使用哪種處理程序來處理請求。HttpApplication 對象還負責檢測對動態創建的、表示資源的程序集(如 .aspx 頁面或 .asmx Web 服務)所進行的更改。如果檢測到更改,應用程序對象將確保編譯并加載所請求的資源的最新來源。
臨時文件和頁面程序集 要全面了解 ASP.NET HTTP 運行時,讓我們來分析一下當請求 ASP.NET 頁面時,文件系統層所發生的變化。接下來,您將了解由 HTTP 管道的對象管理和監視的一組動態創建的臨時文件。
雖然可以將頁面的核心代碼隔離在代碼背后的 C# 或 Microsoft? Visual Basic? .NET 類中,但可以將 Web 頁面編寫和部署為 .aspx 文本文件。對于要顯示為 URL 的頁面來說,.aspx 文件在應用程序的 Web 空間中必須始終可用。.aspx 文件的實際內容將確定應用程序對象要加載的程序集(或多個程序集)。
按照設計,HttpApplication 對象將查找一個根據請求的 ASPX 文件命名的類。如果頁面命名為 sample.aspx,則要加載的相應的類名為 ASP.sample_aspx。應用程序對象在 Web 應用程序的所有程序集文件夾中查找這樣的類,這些文件夾包括全局程序集緩存 (GAC)、Bin 子文件夾和 Temporary ASP.NET Files 文件夾。如果未找到這樣的類,HTTP 結構將分析 .aspx 文件的源代碼,創建一個 C# 或 Visual Basic .NET 類(具體創建哪種類,取決于 .aspx 頁面上設置的語言),同時對其進行編譯。新創建的程序集的名稱是隨機生成的,位于特定于應用程序的子文件夾中,路徑如下所示: 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。再次訪問頁面時,程序集就已存在,不需要重新創建。但是,HttpApplication 對象是如何確定特定于頁面的程序集是否存在呢?它每次都要掃描大量文件夾嗎?不,并不是這樣。
應用程序對象只查看 Temporary ASP.NET Files 文件夾中某個特殊文件夾的內容。具體路徑(特定于應用程序的路徑)由 HttpRuntime.CodegenDir 屬性返回。如果是第一次訪問 .aspx 文件(即還未創建頁面程序集),則該文件夾中就不存在以 ASPX 頁面名稱開頭的 XML 文件。例如,具有動態程序集的 sample.aspx 頁面應有如下的條目:
sample.aspx.XXXXX.xml XXXXX 占位符是一種散列代碼。通過讀取該 XML 文件的內容,應用程序對象就可以了解要加載的程序集的名稱以及要在其中獲取的類。以下代碼片段是這種 Helper 文件的典型內容。包含 ASP.sample_aspx 類的程序集的名稱是 mvxvx8xr。
小結 ASP.NET 應用程序有兩大特征:進程模型和頁面對象模型。ASP.NET 提前使用了 IIS 6.0 的一些功能,而 IIS 6.0 則是 Windows Server 2003 中提供的全新的、開創性的 Microsoft Web 信息服務。尤其值得一提的是,在獨立的輔助進程中運行的 ASP.NET 應用程序,其行為與 IIS 6 中的所有應用程序相同。而且,盡管會出現運行時異常、內存泄露或程序錯誤,ASP.NET 運行時仍能自動回收輔助進程以保證實現卓越的性能。這種功能已成為 IIS 6.0 的系統功能。
在本文中,我概括介紹了默認的 ASP.NET 進程模型的基礎知識,以及 IIS 級代碼(ASP.NET ISAPI 擴展)和輔助進程之間的交互。同時,還介紹了與 IIS 6 進程模型之間的最新區別。本文對頁面對象模型的論述較少,我將在以后的文章中進一步介紹。歡迎繼續閱讀!
要深入了解 ASP.NET、HTTP 運行時和頁面對象模型,請查閱 Microsoft Press 2003 年出版的我的新書 Programming Microsoft ASP.NET。