天天看點

DotText源碼學習——ASP.NET的工作機制

——本文是《項目驅動學習——DotText源碼學習》系列的第一篇文章,在這之後會持續發表相關的文章。

在閱讀DotText源碼之前,讓我們首先了解一下ASP.NET的工作機制,可以使我們更好的了解。ASP.NET是Web伺服器(IIS)的ISAPI(Internet Server API)擴充。當IIS接收到用戶端浏覽器發來的請求後,它根據請求的檔案類型确定由哪個ISAPI擴充來處理該請求,并将請求轉發給ASP.NET(如果是ASP.NET處理的相應檔案類型的話,如*.aspx、*.asmx、*.ashx)。ASP.NET應用首先進行初始化,并裝載配置子產品,然後經過一系列步驟來完成對用戶端請求的響應。

下面按以下步驟來解析ASP.NET的工作機制:

Step1:使用者從浏覽器中請求網頁(.aspx)

Step2:ASP.NET接收到對應用程式的第一個請求

Step3:為每個請求建立ASP.NET核心對象

Step4:将HttpApplication對象配置設定給請求

Step5:由HttpApplication管線處理請求

當IIS收到請求後,會對所請求檔案的擴充名進行檢查,确定應該由哪個ISAPI擴充來處理該請求,然後将該請求傳遞給合适的ISAPI擴充,也就是說IIS将該請求傳給ASP.NET。

說明: 1、ASP.NET即是IIS的ISAPI擴充,并且ASP.NET處理已映射到它的檔案擴充名,如.aspx、.ascx、.ashx和.asmx

IIS是如何将請求傳給ASP.NET的呢,或者說他們是怎麼通信的呢?其實,IIS捕獲的任何請求經過檢查分析,然後映射到一個外部子產品進行真正的處理。而負責處理輸入的ASP.NET請求的外部子產品,是一個名為aspnet_isapi的動态連結庫(DLL)——<b>aspnet_isapi.dll</b>。該子產品并不是一個普通的DLL,而是一個ISAPI子產品。ISAPI子產品是實作了一種特殊協定的DLL,能夠與IIS可執行檔案通信。

下面以IIS6的程序模型為例,說明這個過程(注意:不同的IIS版本這個過程是有差異的)。

IIS 6.0程序模型,也稱為工作程序隔離模式(worker process isolation mode),是以<b>應用程式池</b>的概念為中心的。IIS6.0總會保持一個單獨的工作程序——應用程式池。所有的處理都發生在這個程序裡,包括ISAPI DLL的執行。應用程式池是一組共享相同的工作程序副本的Web應用程式,進而将Web伺服器的核心部分與可能無法正常工作的應用程式相分離。我們可以用一組不同的屬性來配置每個應用程式池及其工作程序副本。

在預設的IIS 6.0程序模型下運作時,ASP.NET應用程式使用一個通用的、與ASP.NET無關的(ASP.NET-agnostic)工作程序——這也是服務Web伺服器托管的所有應用程式的工作程序,該程式名為<b>w3wp.exe</b>。在IIS6.0裡,ISAPI擴充運作在應用程式池的工作程序裡。而.NET運作時也運作在這個程序裡,所有ISAPI擴充和.NET運作時的通信時發生在程序内的,這就使得性能更高。

配置設定給同一個應用程式池的所有Web應用程式共享該可執行程式的一個副本。IIS 6.0構架的另一個關鍵元件是名為http.sys的核心模式裝置驅動程式。<b>該驅動程式是負責捕獲并服務任何輸入請求的HTTP監聽程式。</b>

<b>當一個請求到達時,http.sys把它傳遞到被調用應用程式所屬的應用程式池管理的隊列。每個應用程式池有一個隊列。w3wp.exe工作程序裝入aspnet_isapi.dll;接着該ISAPI擴充裝入公共語言運作庫(common language runtime,簡稱CLR),啟動ASP.NET運作庫管道來處理請求。如果IIS 6.0程序模型正在使用,内置的ASP.NET工作程序将被禁用。工作程序使用http.sys擷取請求,并把響應發送給用戶端。</b>

就這樣一個請求通過IIS6.0被轉到ASP.NET進行處理。下面用一個圖來形象描述。

<a href="http://blog.51cto.com/attachment/201008/141613733.png" target="_blank"></a>

Step2、ASP.NET接收到對應用程式的第一個請求

當ASP.NET接收到對應用程式中任何資源的第一個請求時,應用程式管理器(ApplicactionManager)就會建立一個應用程式域;在應用程式域中,将建立宿主環境(HostingEnviroment類的執行個體),它提供對有關應用程式的資訊的通路。

1、應用程式域(AppDomain)為全局變量提供應用程式隔離,在其中可以加載和執行托管代碼程式集,并允許單獨解除安裝每個應用程式,但不允許解除安裝單個程式集隻能通過解除安裝應用程式域來解除安裝程式集。 2、HostingEnvironment類,在托管應用程式的應用程式域(AppDomain)内向托管應用程式提供<b>應用程式管理功能</b>和<b>應用程式服務</b>。

如下圖所示:

<a href="http://blog.51cto.com/attachment/201008/141644373.png" target="_blank"></a>

應用程式域(AppDomain)是怎麼建立的呢?其實是這麼回事:從<b>Step1</b>知道接收到請求後IIS6.0的w3wp.exe工作程序将裝入aspnet_isapi.dll,接着該ISAPI擴充裝入CLR,啟動ASP.NET運作庫管道來處理請求。在aspnet_isapi.dll理是通過調用ISAPIRuntime派生類的執行個體進入.NET運作時的,這是因為IISAPIRuntime接口擔當着來自于ISAPI擴充的非托管代碼和托管代碼之間的橋梁。

其實,一旦運作時啟動并運作起來,ISAPI擴充就可以調用ISAPIRuntime.ProcessRequest()方法了,而這個方法就是進入ASP.NET通道真正的登入點。經過<b>Step2</b>後,請求它将被路由到ISAPIRuntime.ProcessRequest()方法裡。這個方法會接着調用<b>HttpRuntime.ProcessRequest</b>,在這個方法裡,做了幾件重要的事情:

為請求建立了一個新的<b>HttpContex</b>t執行個體

擷取一個<b>HttpApplication</b>執行個體

調用<b>HttpApplication.Init()</b>初始化管道事件

Init()觸發<b>HttpApplication.ResumeProcessing()</b>,啟動ASP.NET管道處理。

初始化所有核心應用程式對象之後,将通過建立HtppApplication類的執行個體啟動應用程式。如果應用程式具有Global.asax檔案,則ASP.NET會建立Global.asax類(從HttpApplication類派生)的一個執行個體,并使用該派生類表示應用程式。同時,ASP.NET将建立所有已配置的子產品(如狀态管理子產品、安全管理子產品),在建立完所有已配置的子產品後,将調用HttpApplication類的Init方法。

Global.asax裡的事件處理器會自動映射到對應的事件,也可以映射到額外添加的HttPModules,這些HttPModules本質上是HttpApplication已釋出事件的一種擴充。我們可以自己定一些HttpModules和HttpHandlers,然後通過在web.config裡注冊,HttPModules和HttpHandlers可以被動态的加載,并且可以添加到事件鍊條上。HttPModules實際上就是事件處理器,它可以鈎住指定HttpApplication的事件。而HttpHandlers就是一個端點,它可以被調用處理“應用程式級的請求處理”。HttPModules和HttpHandlers将被加載,然後添加到調用鍊上作為HttpApplication.Init()方法調用的一部分。

<a href="http://blog.51cto.com/attachment/201008/141730862.png" target="_blank"></a>

說明:每一個請求都将被路由到一個HttpApplication對象。HttpApplicationFactory類會為你的ASP.NET程式建立一個HttpApplication對象池,它負責加載程式和給每一個到來的請求分發HttpApplication的引用(由<b>Step2</b>知道這些是在ISAPIRuntime.ProcessRequest()方法中調用HttpRuntime.ProcessRequest()完成的)。

在該階段由HttpApplication類執行一系列事件;并根據所請求資源的檔案擴充名(在應用程式的配置檔案中映射),選擇實作了<b>IHttpHandler</b>的類來對請求處理(即由一些HttpHandlers處理)。

HttpApplication主要用作HTTP管道的事件控制器,是以,它的接口主要有事件組成,這些事件包括:

BeginRequest

AuthenticateRequest

AuthorizeRequest

ResolveRequestCache

AquireRequestState

PreRequestHandlerExecute

<b>…Handler Execution…</b>

PostRequestHandlerExecute

ReleaseRequestState

UpdateRequestCache

EndRequest

ASP.NET管道一旦啟動,HttpApplication将逐一觸發事件,如上所述的事件。每一個事件都将被觸發,如果事件綁定了事件處理器,那麼這些事件處理器将被調用,執行它們的任務。這個過程的主要目的是通過調用HttpHandler處理指定的請求。對于ASP.NET請求而言,HttpHandler是處理請求機制的核心,在這裡任意的應用程式級的代碼被執行。

如果該請求針對從Page類派生的對象(頁),并且需要對該頁進行編譯,則ASP.NET會在建立該頁的執行個體之前對其進行編譯,在裝載後用該執行個體來處理這個請求,處理完後通過HttpRespone輸出,最後釋放該執行個體。

【1】微軟公司著,《Web應用開發——ASP.NET2.0》29~32頁,高等教出版社

【2】Esposito, D.著,《ASP.NET 2.0進階程式設計》1.1.1 節ASP.NET程序模型,清華大學出版社

如果想知道得更清楚請閱讀上述博文(推薦,因為書籍不一定有)或書籍。

     本文轉自Saylor87 51CTO部落格,原文連結:http://blog.51cto.com/skynet/366345,如需轉載請自行聯系原作者

繼續閱讀