ASP.NET HTTP運(yùn)行時(shí)組成詳細(xì)說明
發(fā)表時(shí)間:2024-02-20 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]簡介 不管使用哪種底層平臺(tái),可靠性和性能都是對(duì)所有 Web 應(yīng)用程序的主要要求,盡管從某種意義上講,這兩個(gè)要求是相互矛盾的。例如,要構(gòu)建更可靠、更健壯的應(yīng)用程序,可能需要將 Web 服務(wù)器與具體的應(yīng)用程序分離,使應(yīng)用程序在進(jìn)程外工作。但是,如果在不同于 Web 服務(wù)器進(jìn)程的內(nèi)存環(huán)境中工作,應(yīng)用程...
簡介
不管使用哪種底層平臺(tái),可靠性和性能都是對(duì)所有 Web 應(yīng)用程序的主要要求,盡管從某種意義上講,這兩個(gè)要求是相互矛盾的。例如,要構(gòu)建更可靠、更健壯的應(yīng)用程序,可能需要將 Web 服務(wù)器與具體的應(yīng)用程序分離,使應(yīng)用程序在進(jìn)程外工作。但是,如果在不同于 Web 服務(wù)器進(jìn)程的內(nèi)存環(huán)境中工作,應(yīng)用程序?qū)⒆兟。因此,需要采取合理的措施,以確保進(jìn)程外代碼盡可能快地運(yùn)行。
在構(gòu)建 Microsoft? ASP.NET 運(yùn)行時(shí)環(huán)境時(shí),依據(jù)的設(shè)計(jì)原則即:充分考慮可靠性和性能。得到的 ASP.NET 進(jìn)程模型包含了兩個(gè)系統(tǒng)元素 - 一個(gè)存在于 Web 服務(wù)器進(jìn)程中的進(jìn)程內(nèi)連接器,一個(gè)外部的輔助進(jìn)程。另外,ASP.NET 運(yùn)行時(shí)結(jié)構(gòu)的可伸縮能力很強(qiáng),可以自動(dòng)使用多處理器硬件中任意選定的處理器。這種模式被稱為“Web Garden”,它可以使多個(gè)輔助進(jìn)程同時(shí)運(yùn)行,而且各個(gè)進(jìn)程均在獨(dú)立的處理器中。
高度概括起來,ASP.NET 運(yùn)行時(shí)具有三大屬性:
應(yīng)用程序和 ASP.NET 輔助進(jìn)程之間完全分離。提供服務(wù)的輔助進(jìn)程的壽命決不會(huì)影響應(yīng)用程序的壽命。換句話說,當(dāng)應(yīng)用程序啟動(dòng)并處于運(yùn)行狀態(tài)時(shí),輔助進(jìn)程可以隨時(shí)終止。
盡管 ASP.NET 應(yīng)用程序從不在 Web 服務(wù)器內(nèi)采用進(jìn)程內(nèi)的方式運(yùn)行,但大多數(shù)情況下,其總體性能仍接近于進(jìn)程內(nèi)應(yīng)用程序的性能。
為 Web Garden 體系結(jié)構(gòu)提供了內(nèi)置的和可配置的支持。只要簡單檢查一下配置文件中的設(shè)置,輔助進(jìn)程就可以克隆自己,以利用所有與進(jìn)程密切相關(guān)的 CPU。因此,在大多數(shù)情況下,您在具備多處理器的計(jì)算機(jī)中獲得的可縮放性將呈線性增長的趨勢(shì)。(本文后面將詳細(xì)介紹此內(nèi)容。)
本文將介紹 ASP.NET 運(yùn)行時(shí)環(huán)境的組成元素,然后一步一步地講述從 URL 請(qǐng)求變?yōu)榧?HTML 文本的“漫長而曲折”的過程。
除非另有說明,否則以下介紹中均指 ASP.NET 的默認(rèn)進(jìn)程模型,即 Microsoft? Internet Information Services (IIS) 5.x 中唯一的模型。
ASP.NET 結(jié)構(gòu)的組件
執(zhí)行 ASP.NET 應(yīng)用程序需要宿主 Web 服務(wù)器的支持。在 Microsoft? Windows? 的 Server 平臺(tái)中,Web 服務(wù)器由名為 inetinfo.exe 的 IIS 可執(zhí)行文件表示。Windows 2000 及以上版本的操作系統(tǒng)本身均提供了 Web 服務(wù)器。但需要注意,在 Microsoft? Windows Server™ 2003 中,并未默認(rèn)安裝 IIS 和 ASP.NET,必須通過單擊“控制面板”中的“添加或刪除程序”小程序?qū)⑵涮砑拥较到y(tǒng)中。
IIS 是一個(gè)未托管的可執(zhí)行程序,它提供了一個(gè)基于 ISAPI 擴(kuò)展模塊和篩選器模塊的可擴(kuò)展模型。通過編寫此類模塊,開發(fā)人員可以直接管理對(duì)特定資源類型的請(qǐng)求,并在各個(gè)預(yù)定義的步驟中接收當(dāng)前請(qǐng)求。擴(kuò)展和篩選器是一些 DLL,可以導(dǎo)出一些具有已知名稱和簽名的函數(shù)。這些插件組件是在 IIS 配置數(shù)據(jù)庫中注冊(cè)并配置的。
只有少數(shù)幾種被客戶端請(qǐng)求的資源類型由 IIS 直接處理。例如,對(duì) HTML 頁面、文本文件、JPEG 和 GIF 圖像的傳入請(qǐng)求由 IIS 處理。對(duì) Active Server Page (*.asp) 文件的請(qǐng)求通過調(diào)用名為 asp.dll 的 ASP 專用擴(kuò)展模塊進(jìn)行解析。同樣,對(duì) ASP.NET 資源(例如,*.aspx、*.asmx、*.ashx)的請(qǐng)求將傳遞到 ASP.NET ISAPI 擴(kuò)展。該系統(tǒng)組件是一個(gè)名為 aspnet_isapi.dll 的 Win32 DLL。ASP.NET 擴(kuò)展可以處理多種資源類型,包括 Web 服務(wù)和 HTTP 處理程序調(diào)用。
ASP.NET ISAPI 擴(kuò)展是一個(gè) Win32 DLL,未集成托管代碼。它是接收和分派對(duì)各種 ASP.NET 資源的請(qǐng)求的控制中心。按照設(shè)計(jì),該模塊存在于 IIS 進(jìn)程中,在具有管理員權(quán)限的 SYSTEM 帳戶下運(yùn)行。開發(fā)人員和系統(tǒng)管理員不能修改此帳戶。ASP.NET ISAPI 擴(kuò)展負(fù)責(zé)調(diào)用 ASP.NET 輔助進(jìn)程 (aspnet_wp.exe),而該進(jìn)程又負(fù)責(zé)控制請(qǐng)求的執(zhí)行。除了對(duì)請(qǐng)求進(jìn)行安排以外,ASP.NET ISAPI 還監(jiān)視輔助進(jìn)程的運(yùn)行情況,并在性能降低到一定程度時(shí)將進(jìn)程取消。
輔助進(jìn)程是一小段 Win32 shell 代碼,集成了公共語言運(yùn)行庫 (CLR) 并運(yùn)行托管代碼。它負(fù)責(zé)處理對(duì) ASPX、ASMX 和 ASHX 資源的請(qǐng)求。一般來說,此進(jìn)程在一臺(tái)給定的計(jì)算機(jī)中只有一個(gè)實(shí)例。所有當(dāng)前激活的 ASP.NET 應(yīng)用程序均在其中運(yùn)行,每個(gè)應(yīng)用程序都位于一個(gè)獨(dú)立的 AppDomain 中。但是,如前所述,輔助進(jìn)程支持 Web Garden 模式,即進(jìn)程的相同副本都運(yùn)行在與進(jìn)程密切相關(guān)的 CPU 中。(更多內(nèi)容,請(qǐng)參閱本文后面的“Web Garden 模型”部分。)
ISAPI 和輔助進(jìn)程之間的通訊是使用一組命名管道進(jìn)行的。命名管道是一種 Win32 機(jī)制,用于跨進(jìn)程邊界傳輸數(shù)據(jù)。顧名思義,命名管道的工作方式與管道相似:在一端輸入數(shù)據(jù),在另一端輸出相同的數(shù)據(jù)。建立的管道既可以連接本地進(jìn)程,也可以連接遠(yuǎn)程計(jì)算機(jī)上運(yùn)行的進(jìn)程。對(duì)于本地進(jìn)程間通訊,管道是 Windows 中的最有效、最靈活的工具。
為確保獲得最優(yōu)性能,aspnet_isapi 使用異步命名管道來將請(qǐng)求轉(zhuǎn)發(fā)給輔助進(jìn)程并獲得響應(yīng)。另一方面,輔助進(jìn)程在需要查詢有關(guān) IIS 環(huán)境的信息(即服務(wù)器變量)時(shí)又使用同步管道。aspnet_isapi 模塊創(chuàng)建固定數(shù)量的命名管道,并使用重疊的操作以通過小的線程池處理同一時(shí)間進(jìn)行的連接。當(dāng)通過管道進(jìn)行的數(shù)據(jù)交換操作結(jié)束后,完成例程將斷開客戶端,并重新使用管道實(shí)例為新的客戶端服務(wù)。線程池和重疊操作均可以保證使 ASP.NET ISAPI 的性能達(dá)到令人滿意的水平。但是,aspnet_isapi 擴(kuò)展決不會(huì)處理 HTTP 請(qǐng)求。
ASP.NET 請(qǐng)求的處理邏輯可以概括為以下步驟:
當(dāng)請(qǐng)求到達(dá)時(shí),IIS 檢查資源類型并調(diào)用 ASP.NET ISAPI 擴(kuò)展。如果啟用了默認(rèn)的進(jìn)程模型,aspnet_isapi 會(huì)將請(qǐng)求排隊(duì),并將請(qǐng)求分配給輔助進(jìn)程。所有的請(qǐng)求數(shù)據(jù)都通過異步 I/O 發(fā)送。如果啟用了 IIS 6 進(jìn)程模型,請(qǐng)求將自動(dòng)在輔助進(jìn)程 (w3wp.exe) 中排隊(duì),此輔助進(jìn)程用于處理應(yīng)用程序所屬的 IIS 應(yīng)用程序池。IIS 6 輔助進(jìn)程不了解 ASP.NET 和托管代碼的任何情況,它只是處理 *.aspx 擴(kuò)展并加載 aspnet_isapi 模塊。當(dāng) ASP.NET ISAPI 在 IIS 6 進(jìn)程模型中運(yùn)行時(shí),它的工作方式有所不同,僅在 w3wp.exe 輔助進(jìn)程的上下文中加載 CLR。
收到請(qǐng)求后,ASP.NET 輔助進(jìn)程將通知 ASP.NET ISAPI,它將為請(qǐng)求服務(wù)。通知通過同步 I/O 實(shí)現(xiàn)。之所以使用同步模型,是因?yàn)檎?qǐng)求只有在 ISAPI 內(nèi)部請(qǐng)求表中被標(biāo)記為“executing”,輔助進(jìn)程才能開始處理它。如果請(qǐng)求已經(jīng)由特殊的輔助進(jìn)程進(jìn)行處理,則不能再將它指定到其他進(jìn)程,除非原始進(jìn)程已取消。
在輔助進(jìn)程的上下文中執(zhí)行請(qǐng)求。有時(shí),輔助進(jìn)程可能需要回調(diào) ISAPI 以完成請(qǐng)求,也就是需要說枚舉服務(wù)器變量。這種情況下,輔助進(jìn)程將使用同步管道,因?yàn)檫@樣可以保持請(qǐng)求處理邏輯的順序。
完成后,響應(yīng)被發(fā)送到打開了異步管道的 aspnet_isapi,F(xiàn)在,請(qǐng)求的狀態(tài)變?yōu)椤癉one”,之后將從請(qǐng)求表中被刪除。如果輔助進(jìn)程崩潰,正在處理的所有請(qǐng)求仍將保持“executing”狀態(tài)并持續(xù)一段時(shí)間。如果 aspnet_isapi 檢測(cè)到輔助進(jìn)程已取消,它將自動(dòng)終止請(qǐng)求并釋放所有相關(guān)的 IIS 資源。
以上說明是指默認(rèn)的 ASP.NET 進(jìn)程模型,即在 IIS 5.x 中運(yùn)行的工作模型。IIS 6(Windows Server 2003 提供)的默認(rèn)工作方式對(duì) ASP.NET 進(jìn)程模型也有影響。當(dāng)集成在 IIS 6.0 中時(shí),ASP.NET 1.1 會(huì)自動(dòng)調(diào)整自己的工作方式以適應(yīng)宿主環(huán)境。這時(shí),不再需要使用 aspnet_wp 輔助進(jìn)程,machine.config 文件中定義的某些配置參數(shù)也被忽略。從 ASP.NET 的角度來看,IIS 6 的最大改變是有關(guān)請(qǐng)求的一切都在 aspnet_isapi 的控制之下,且都處在 w3wp.exe 輔助進(jìn)程的上下文中。輔助進(jìn)程的帳戶是為 Web 應(yīng)用程序所屬的應(yīng)用程序池設(shè)置的帳戶。默認(rèn)情況下,該帳戶是 NETWORKSERVICE—,它是一個(gè)內(nèi)置的弱帳戶,在功能上與 ASPNET 等價(jià)。
輔助進(jìn)程受一個(gè)名為進(jìn)程回收 (Recycling) 的功能的控制。進(jìn)程回收具有 aspnet_isapi 功能,當(dāng)現(xiàn)有進(jìn)程消耗的內(nèi)存太多、響應(yīng)太慢或掛起時(shí)可以自動(dòng)啟動(dòng)新進(jìn)程。出現(xiàn)這種情況時(shí),新請(qǐng)求將由新實(shí)例處理,新實(shí)例從而變成新的活動(dòng)進(jìn)程。但是,指定給舊進(jìn)程的所有請(qǐng)求仍保持掛起狀態(tài)。如果舊進(jìn)程結(jié)束了掛起的請(qǐng)求并進(jìn)入空閑狀態(tài),該進(jìn)程即終止。如果輔助進(jìn)程崩潰,或者由于其他原因停止處理請(qǐng)求,則所有掛起的請(qǐng)求將被重新指定給新進(jìn)程。
盡管 ASP.NET ISAPI 和輔助進(jìn)程是 ASP.NET 運(yùn)行時(shí)結(jié)構(gòu)的主要組成部分,但還有其他一些可執(zhí)行文件也發(fā)揮著作用。下表列出了所有這些組件。
表 1:構(gòu)成 ASP.NET 運(yùn)行時(shí)環(huán)境的可執(zhí)行文件
名稱 | 類型 | 帳戶 |
aspnet_isapi.dll | Win32 DLL(ISAPI 擴(kuò)展) | 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 組件是一個(gè)小的 Win32 ISAPI 篩選器,用來備份 ASP.NET 應(yīng)用程序的無 Cookie 會(huì)話狀態(tài)。在 Windows Server 2003 中,當(dāng)啟用 IIS 6 進(jìn)程模型時(shí),aspnet_filter.dll 還將篩選出 Bin 目錄中對(duì)非可執(zhí)行資源的請(qǐng)求。
aspnet_state.exe 的作用對(duì) Web 應(yīng)用程序更為重要,因?yàn)樗糜诠芾頃?huì)話狀態(tài)。該項(xiàng)服務(wù)是可選的,可以用來在 Web 應(yīng)用程序內(nèi)存空間之外保存會(huì)話狀態(tài)數(shù)據(jù)。該可執(zhí)行文件是一種 NT 服務(wù),既可以在本地運(yùn)行,也可以遠(yuǎn)程運(yùn)行。當(dāng)該服務(wù)被激活后,可以將 ASP.NET 應(yīng)用程序配置為將所有會(huì)話信息保存在此進(jìn)程的內(nèi)存中。一種類似的方案是提供更為可靠的數(shù)據(jù)存儲(chǔ)方式,不受進(jìn)程回收和 ASP.NET 應(yīng)用程序故障的影響。該服務(wù)在 ASPNET 本地帳戶下運(yùn)行,但可以使用服務(wù)控制管理器 (Service Control Manager) 接口來配置它。
另一個(gè)應(yīng)該介紹的可執(zhí)行文件是 aspnet_regiis.exe,盡管嚴(yán)格來講,它并不屬于 ASP.NET 運(yùn)行時(shí)結(jié)構(gòu)。該實(shí)用程序可以用來配置環(huán)境,以在一臺(tái)計(jì)算機(jī)上并行執(zhí)行不同版本的 ASP.NET,還可用于維修 IIS 和 ASP.NET 損壞的配置。該實(shí)用程序的工作方式是更新存儲(chǔ)在 IIS 配置數(shù)據(jù)庫的根目錄和子目錄中的腳本映射。腳本映射是資源類型和 ASP.NET 模塊之間的一種關(guān)聯(lián)關(guān)系。最后,還可以使用該工具來顯示已安裝的 ASP.NET 版本的狀態(tài),執(zhí)行其他配置操作,如授予對(duì)特定文件夾的 NTFS 權(quán)限、創(chuàng)建客戶腳本目錄。
Web Garden 模型
Web Garden 模型可以通過 machine.config 文件中的 <processModel> 部分進(jìn)行配置。請(qǐng)注意,<processModel> 部分是唯一不能放在應(yīng)用程序特定的 web.config 文件中的配置部分。這就是說,Web Garden 模式可以應(yīng)用到計(jì)算機(jī)中運(yùn)行的所有應(yīng)用程序。但通過使用 machine.config 源文件中的 <location> 節(jié)點(diǎn),可以針對(duì)各個(gè)應(yīng)用程序調(diào)節(jié)計(jì)算機(jī)的設(shè)置。
。紁rocessModel> 部分有兩個(gè)屬性可以影響 Web Garden 模型,它們是 webGarden 和 cpuMask。webGarden 屬性接受布爾值,表示是否使用了多個(gè)輔助進(jìn)程(一個(gè)相關(guān)的 CPU 對(duì)應(yīng)一個(gè)進(jìn)程)。默認(rèn)情況下,該屬性的值為 false。cpuMask 屬性保存一個(gè) DWORD 值,該值的二進(jìn)制表示為能夠運(yùn)行 ASP.NET 輔助進(jìn)程的 CPU 提供了位屏蔽。其默認(rèn)值為 -1 (0xFFFFFF),表示可以使用所有可用的 CPU。如果 webGarden 屬性為 false,則 cpuMask 屬性的內(nèi)容將被忽略。cpuMask 屬性還為正在運(yùn)行的 aspnet_wp.exe 的副本數(shù)設(shè)置了上限。
常言道“閃光的不都是金子”,用在這里很合適。Web Garden 模式使得多個(gè)輔助進(jìn)程可以同時(shí)運(yùn)行。但是,需要注意的是所有進(jìn)程都會(huì)有自己的應(yīng)用程序狀態(tài)、進(jìn)程內(nèi)會(huì)話狀態(tài)、ASP.NET 緩存、靜態(tài)數(shù)據(jù)以及運(yùn)行應(yīng)用程序所需的其他內(nèi)容。啟用 Web Garden 模式之后,ASP.NET ISAPI 將根據(jù) CPU 的數(shù)量盡可能多地啟動(dòng)輔助進(jìn)程,每個(gè)輔助進(jìn)程都是下一進(jìn)程的完整克。恳贿M(jìn)程都與相應(yīng)的 CPU 密切相關(guān))。為平衡工作負(fù)荷,傳入的請(qǐng)求以單循環(huán)的方式在運(yùn)行的進(jìn)程之間進(jìn)行劃分。輔助進(jìn)程就象在單處理器中一樣被回收。請(qǐng)注意,ASP.NET 繼承了操作系統(tǒng)中所有的 CPU 使用限制,并且不包括實(shí)現(xiàn)限制的自定義語義。
總之,Web Garden 模型并不適用于所有應(yīng)用程序。應(yīng)用程序的狀態(tài)越多,其的性能損失也越多。工作數(shù)據(jù)存儲(chǔ)在共享內(nèi)存的塊中,以便一個(gè)進(jìn)程輸入的變化可以立即被其他進(jìn)程得知。但是,處理請(qǐng)求時(shí),工作數(shù)據(jù)被復(fù)制到進(jìn)程的上下文中。因此,各個(gè)輔助進(jìn)程將處理自己的工作數(shù)據(jù),而應(yīng)用程序的狀態(tài)越多,性能損失就越大。鑒于此,仔細(xì)、明智的應(yīng)用程序基準(zhǔn)測(cè)試是絕對(duì)必要的。
只有重啟 IIS 后,對(duì)配置文件中 <processModel> 部分所做的更改才會(huì)生效。在 IIS 6 中,Web Garden 模式的參數(shù)保存在 IIS 配置數(shù)據(jù)庫中,webGarden 和 cpuMask 屬性被忽略。
HTTP 管道
ASP.NET ISAPI 擴(kuò)展啟動(dòng)輔助進(jìn)程后,它將傳遞部分命令行參數(shù)。輔助進(jìn)程使用這些參數(shù)來執(zhí)行加載 CLR 前需要執(zhí)行的任務(wù)。傳遞的值包括:COM 和 DCOM 安全性所要求的身份驗(yàn)證等級(jí)、可以使用的命名管道的數(shù)量和 IIS 進(jìn)程標(biāo)識(shí)。命名管道的名稱是使用 IIS 進(jìn)程標(biāo)識(shí)和允許的管道數(shù)隨機(jī)生成的。輔助進(jìn)程不接收可用管道的名稱,但可以接收識(shí)別管道名稱所需的信息。
COM 和 DCOM 安全性與 Microsoft? .NET Framework 有何關(guān)系?實(shí)際上,CLR 是作為 COM 對(duì)象提供的。更準(zhǔn)確地說,CLR 本身不是由 COM 代碼構(gòu)成的,但是指向 CLR 的接口卻是一個(gè) COM 對(duì)象。因此,輔助進(jìn)程加載 CLR 的方式與加載 COM 對(duì)象的方式相同。
當(dāng) ASPX 請(qǐng)求遇到 IIS 時(shí),Web 服務(wù)器將根據(jù)選擇的身份驗(yàn)證模型(匿名、Windows、Basic 或 Digest)來分配一個(gè)令牌。當(dāng)輔助進(jìn)程收到要處理的請(qǐng)求時(shí),令牌被傳遞到輔助進(jìn)程。請(qǐng)求由輔助進(jìn)程中的線程獲取。該線程從最初獲取傳入請(qǐng)求的 IIS 線程繼承身份令牌。在 aspnet_wp.exe 中,負(fù)責(zé)處理請(qǐng)求的實(shí)際帳戶取決于在特殊的 ASP.NET 應(yīng)用程序中是如何配置模擬的。如果模擬被禁用(默認(rèn)設(shè)置),則線程將在輔助進(jìn)程的帳戶下運(yùn)行。默認(rèn)情況下,該帳戶在 ASP.NET 進(jìn)程模型中為 ASPNET,在 IIS 6 進(jìn)程模型中為 NETWORKSERVICE。這兩個(gè)帳戶都是“弱”帳戶,提供的功能比較有限,可以有效抵擋回復(fù)性攻擊 (Revert-to-self Attack)。(回復(fù)性攻擊是指將模擬的客戶端的安全性令牌回復(fù)到父進(jìn)程令牌。為輔助進(jìn)程分配弱帳戶可以挫敗此類攻擊。)
高度概括起來,ASP.NET 輔助進(jìn)程完成的一項(xiàng)主要任務(wù)就是將請(qǐng)求交給一系列稱為的 HTTP 管道的托管對(duì)象。要激活 HTTP 管道,可以創(chuàng)建一個(gè) HttpRuntime 類的新實(shí)例,然后調(diào)用其 ProcessRequest 方法。如前所述,ASP.NET 中始終只運(yùn)行一個(gè)輔助進(jìn)程(除非啟用了 Web Garden 模型),該進(jìn)程在獨(dú)立的 AppDomain 中管理所有的 Web 應(yīng)用程序。每個(gè) AppDomain 都有自己的 HttpRuntime 類實(shí)例,即管道中的輸入點(diǎn)。HttpRuntime 對(duì)象初始化一系列有助于實(shí)現(xiàn)請(qǐng)求的內(nèi)部對(duì)象。Helper 對(duì)象包括緩存管理器(Cache 對(duì)象)和內(nèi)部文件系統(tǒng)監(jiān)視器(用于檢測(cè)構(gòu)成應(yīng)用程序的源文件的更改)。HttpRuntime 為請(qǐng)求創(chuàng)建上下文,并用與請(qǐng)求相關(guān)的 HTTP 信息填充上下文。上下文用 HttpContext 類的實(shí)例來表示。
另一個(gè)在 HTTP 運(yùn)行時(shí)的設(shè)置初期創(chuàng)建的 Helper 對(duì)象是文本書寫器,用于包含瀏覽器的響應(yīng)文本。文本書寫器是 HttpWriter 類的實(shí)例,此對(duì)象對(duì)頁面代碼以編程方式發(fā)送的文本進(jìn)行緩存。HTTP 運(yùn)行時(shí)被初始化后,它將查找實(shí)現(xiàn)請(qǐng)求的應(yīng)用程序?qū)ο蟆?yīng)用程序?qū)ο笫?HttpApplication 類的實(shí)例,該類就是 global.asax 文件背后的類。global.asax 在編程時(shí)是可選的,但在構(gòu)建結(jié)構(gòu)時(shí)是必需的。因此,如果應(yīng)用程序中沒有構(gòu)建類,則必須使用默認(rèn)對(duì)象。ASP.NET 運(yùn)行時(shí)包括幾個(gè)中間工廠類,可以用來查找并返回有效的 Handler 對(duì)象以處理請(qǐng)求。整個(gè)過程中用到的第一個(gè)工廠類是 HttpApplicationFactory。它的主要任務(wù)是使用 URL 信息來查找 URL 虛擬目錄和匯集的 HttpApplication 對(duì)象之間的匹配關(guān)系。
應(yīng)用程序工廠類的行為可以概括為以下幾點(diǎn):
工廠類維護(hù) HttpApplication 對(duì)象池,并使用它們來處理應(yīng)用程序的請(qǐng)求。池的壽命與應(yīng)用程序的壽命相同。
應(yīng)用程序的第一個(gè)請(qǐng)求到達(dá)時(shí),工廠類提取有關(guān)應(yīng)用程序類型的信息(global.asax 類)、設(shè)置用于監(jiān)視更改的文件、創(chuàng)建應(yīng)用程序狀態(tài)并觸發(fā) Application_OnStart 事件。
工廠類從池中獲取一個(gè) HttpApplication 實(shí)例,并將要處理的請(qǐng)求放入實(shí)例中。如果沒有可用的對(duì)象,則創(chuàng)建一個(gè)新的 HttpApplication 對(duì)象。要?jiǎng)?chuàng)建 HttpApplication 對(duì)象,需要先完成 global.asax 應(yīng)用程序文件的編譯。
HttpApplication 開始處理請(qǐng)求,并且只能在完成這個(gè)請(qǐng)求后才能處理新的請(qǐng)求。如果收到來自同一資源的新請(qǐng)求,則由池中的其他對(duì)象來處理。
應(yīng)用程序?qū)ο笤试S所有注冊(cè)的 HTTP 模塊對(duì)請(qǐng)求進(jìn)行預(yù)處理,并找出最適合處理請(qǐng)求的處理程序類型。這通過查找請(qǐng)求的 URL 的擴(kuò)展和配置文件中的信息來完成。
HTTP 處理程序是一些實(shí)現(xiàn) IHttpHandler 接口的類。.NET Framework 為常見的資源類型提供了一些預(yù)定義的處理程序,包括 ASPX 頁面和 Web 服務(wù)。machine.config 文件中的 <httpHandlers> 部分定義了 HttpApplication 對(duì)象必須實(shí)例化才能處理特定類型資源的請(qǐng)求的類名。如果 Helper 類是一個(gè)處理程序工廠,GetHandler 方法將確定要使用的處理程序類型。這時(shí),將從一組類似的對(duì)象中獲取適當(dāng)類型的處理程序,并對(duì)其進(jìn)行配置以處理請(qǐng)求。
IHttpHandler 接口提供了兩個(gè)方法:IsReusable 和 ProcessRequest。前者將返回一個(gè)布爾值,表示處理程序是否可以被匯集。(大多數(shù)預(yù)定義的處理程序都是匯集的,但是您可以自行定義每次都需要新實(shí)例的處理程序。)ProcessRequest 方法包含處理特定類型資源所需的所有邏輯。例如,ASPX 頁面的處理程序基于以下偽代碼:
private void ProcessRequest()
{
// 確定請(qǐng)求是否是回發(fā) (postback)
IsPostBack = DeterminePostBackMode();
// 觸發(fā) ASPX 源代碼的 Page_Init 事件
PageInit();
// 加載 ViewState,處理已發(fā)送的值。
if (IsPostBack) {
LoadPageViewState();
ProcessPostData();
}
// 觸發(fā) ASPX 源代碼的 Page_Load 事件
PageLoad();
// 1) 再次處理已發(fā)送的值(當(dāng)
// 動(dòng)態(tài)創(chuàng)建控件時(shí))
// 2) 將屬性更改的服務(wù)器端事件提升為輸入驅(qū)動(dòng)的
// 控件(即復(fù)選框的狀態(tài)改變)
// 3) 執(zhí)行與回發(fā)事件相關(guān)的所有代碼
if (IsPostBack) {
ProcessPostDataSecondTry();
RaiseChangedEvents();
RaisePostBackEvent();
}
// 觸發(fā) ASPX 源代碼的 Page_PreRender 事件
PreRender();
// 將控件的當(dāng)前狀態(tài)保存到 ViewState 中
SavePageViewState();
// 將頁面內(nèi)容呈現(xiàn)給 HTML
RenderControl(CreateHtmlTextWriter(Response.Output));
}
無論調(diào)用的資源類型如何,基于 HTTP 處理程序的模型是相同的。唯一隨資源類型變化而變化的元素是處理程序。HttpApplication 對(duì)象負(fù)責(zé)查找應(yīng)該使用哪種處理程序來處理請(qǐng)求。HttpApplication 對(duì)象還負(fù)責(zé)檢測(cè)對(duì)動(dòng)態(tài)創(chuàng)建的、表示資源的程序集(如 .aspx 頁面或 .asmx Web 服務(wù))所進(jìn)行的更改。如果檢測(cè)到更改,應(yīng)用程序?qū)ο髮⒋_保編譯并加載所請(qǐng)求的資源的最新來源。
臨時(shí)文件和頁面程序集
要全面了解 ASP.NET HTTP 運(yùn)行時(shí),讓我們來分析一下當(dāng)請(qǐng)求 ASP.NET 頁面時(shí),文件系統(tǒng)層所發(fā)生的變化。接下來,您將了解由 HTTP 管道的對(duì)象管理和監(jiān)視的一組動(dòng)態(tài)創(chuàng)建的臨時(shí)文件。
雖然可以將頁面的核心代碼隔離在代碼背后的 C# 或 Microsoft? Visual Basic? .NET 類中,但可以將 Web 頁面編寫和部署為 .aspx 文本文件。對(duì)于要顯示為 URL 的頁面來說,.aspx 文件在應(yīng)用程序的 Web 空間中必須始終可用。.aspx 文件的實(shí)際內(nèi)容將確定應(yīng)用程序?qū)ο笠虞d的程序集(或多個(gè)程序集)。
按照設(shè)計(jì),HttpApplication 對(duì)象將查找一個(gè)根據(jù)請(qǐng)求的 ASPX 文件命名的類。如果頁面命名為 sample.aspx,則要加載的相應(yīng)的類名為 ASP.sample_aspx。應(yīng)用程序?qū)ο笤?Web 應(yīng)用程序的所有程序集文件夾中查找這樣的類,這些文件夾包括全局程序集緩存 (GAC)、Bin 子文件夾和 Temporary ASP.NET Files 文件夾。如果未找到這樣的類,HTTP 結(jié)構(gòu)將分析 .aspx 文件的源代碼,創(chuàng)建一個(gè) C# 或 Visual Basic .NET 類(具體創(chuàng)建哪種類,取決于 .aspx 頁面上設(shè)置的語言),同時(shí)對(duì)其進(jìn)行編譯。新創(chuàng)建的程序集的名稱是隨機(jī)生成的,位于特定于應(yīng)用程序的子文件夾中,路徑如下所示: C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files。
子文件夾 v1.1.4322 特定于 ASP.NET 1.1。如果您使用的是 ASP.NET 1.0,子文件夾的版本號(hào)會(huì)有所不同,即子文件夾名為 v1.0.3705。再次訪問頁面時(shí),程序集就已存在,不需要重新創(chuàng)建。但是,HttpApplication 對(duì)象是如何確定特定于頁面的程序集是否存在呢?它每次都要掃描大量文件夾嗎?不,并不是這樣。
應(yīng)用程序?qū)ο笾徊榭?Temporary ASP.NET Files 文件夾中某個(gè)特殊文件夾的內(nèi)容。具體路徑(特定于應(yīng)用程序的路徑)由 HttpRuntime.CodegenDir 屬性返回。如果是第一次訪問 .aspx 文件(即還未創(chuàng)建頁面程序集),則該文件夾中就不存在以 ASPX 頁面名稱開頭的 XML 文件。例如,具有動(dòng)態(tài)程序集的 sample.aspx 頁面應(yīng)有如下的條目:
sample.aspx.XXXXX.xml
XXXXX 占位符是一種散列代碼。通過讀取該 XML 文件的內(nèi)容,應(yīng)用程序?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>
當(dāng)然,只有在分析 filedep 文件的源代碼以生成動(dòng)態(tài)程序集時(shí)才創(chuàng)建該文件。對(duì) filedep 文件所做的任何更改都會(huì)使程序集無效,在下一次請(qǐng)求時(shí)必須重新編譯。需要注意的是,在 ASP.NET 架構(gòu)的未來版本中,該實(shí)現(xiàn)過程可能會(huì)有較大改變。不論什么原因,只要您決定在當(dāng)前應(yīng)用程序中使用它,都必須十分小心。
由于更新而要為頁面創(chuàng)建新的程序集時(shí),ASP.NET 將驗(yàn)證是否可以刪除舊的程序集。如果舊的程序集只包含修改后的頁面的類,ASP.NET 將試圖刪除并替換該程序集,否則將在保留舊程序集的情況下創(chuàng)建一個(gè)新程序集。
在刪除過程中,ASP.NET 可能會(huì)發(fā)現(xiàn)程序集文件已被加載并鎖定。這種情況下,可以為舊程序集添加一個(gè)“.DELETE”擴(kuò)展名,以將其重新命名。(注意,所有 Windows 文件都可以在使用過程中重新命名。)只要應(yīng)用程序重新啟動(dòng)(例如,由于對(duì)某個(gè)應(yīng)用程序文件如 global.asax 和 web.config 進(jìn)行了更改),這些臨時(shí)的 .DELETE 文件就將被刪除。但在處理下一個(gè)請(qǐng)求時(shí),ASP.NET 運(yùn)行時(shí)不會(huì)刪除這些文件。
請(qǐng)注意,默認(rèn)情況下,在整個(gè)應(yīng)用程序重新啟動(dòng)之前,每個(gè) ASP.NET 應(yīng)用程序最多可以重新編譯 15 個(gè)頁面,同時(shí)會(huì)損失一些會(huì)話和應(yīng)用程序數(shù)據(jù)。當(dāng)最近的編譯次數(shù)超過了 <httpRuntime> 部分的 numRecompilesBeforeAppRestart 屬性中設(shè)置的閾值時(shí),將卸載 AppDomain,并重新啟動(dòng)應(yīng)用程序。還要注意,在 .NET Framework 中,您無法卸載單個(gè)程序集。AppDomain 是可以從 CLR 卸載的最小的代碼塊。
小結(jié)
ASP.NET 應(yīng)用程序有兩大特征:進(jìn)程模型和頁面對(duì)象模型。ASP.NET 提前使用了 IIS 6.0 的一些功能,而 IIS 6.0 則是 Windows Server 2003 中提供的全新的、開創(chuàng)性的 Microsoft Web 信息服務(wù)。尤其值得一提的是,在獨(dú)立的輔助進(jìn)程中運(yùn)行的 ASP.NET 應(yīng)用程序,其行為與 IIS 6 中的所有應(yīng)用程序相同。而且,盡管會(huì)出現(xiàn)運(yùn)行時(shí)異常、內(nèi)存泄露或程序錯(cuò)誤,ASP.NET 運(yùn)行時(shí)仍能自動(dòng)回收輔助進(jìn)程以保證實(shí)現(xiàn)卓越的性能。這種功能已成為 IIS 6.0 的系統(tǒng)功能。
在本文中,我概括介紹了默認(rèn)的 ASP.NET 進(jìn)程模型的基礎(chǔ)知識(shí),以及 IIS 級(jí)代碼(ASP.NET ISAPI 擴(kuò)展)和輔助進(jìn)程之間的交互。同時(shí),還介紹了與 IIS 6 進(jìn)程模型之間的最新區(qū)別。