——本文是《項目驅動學習——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 2、isapi(internet server api)伺服器擴充是可以被http伺服器加載和調用的dll。internet伺服器擴充也稱為internet伺服器應用程式(isa),用于增強符 合internet伺服器api(isapi)的伺服器的功能。isa 通過浏覽器應用程式調用,并且将相似的功能提供給通用網關接口 (cgi)
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工作</b>
程序裝入aspnet_isapi.dll;接着該isapi擴充裝入公共語言運作庫(common language
runtime,簡稱clr),啟動asp.net運作庫管道來處理請求。如果iis
6.0程序模型正在使用,内置的asp.net工作程序将被禁用。工作程序使用http.sys擷取請求,并把響應發送給用戶端。
就這樣一個請求通過iis6.0被轉到asp.net進行處理。下面用一個圖來形象描述。
<b>step2、asp.net接收到對應用程式的第一個請求</b>
當asp.net接收到對應用程式中任何資源的第一個請求時,應用程式管理器(applicactionmanager)就會建立一個應用程式域;在應用程式域中,将建立宿主環境(hostingenviroment類的執行個體),它提供對有關應用程式的資訊的通路。
1、應用程式域(appdomain)為全局變量提供應用程式隔離,在其中可以加載和執行托管代碼程式集,并允許單獨解除安裝每個應用程式,但不允許解除安裝單個程式集隻能通過解除安裝應用程式域來解除安裝程式集。 2、hostingenvironment類,在托管應用程式的應用程式域(appdomain)内向托管應用程式提供<b>應用程式管理功能</b>和<b>應用程式服務</b>。
如下圖所示:
應用程式域(appdomain)是怎麼建立的呢?其實是這麼回事:從<b>step1</b>知道接收到請求後iis6.0的w3wp.exe工
作程序将裝入aspnet_isapi.dll,接着該isapi擴充裝入clr,啟動asp.net運作庫管道來處理請求。在
aspnet_isapi.dll理是通過調用isapiruntime派生類的執行個體進入.net運作時的,這是因為iisapiruntime接口擔當
着來自于isapi擴充的非托管代碼和托管代碼之間的橋梁。
将會啟動程式的引導過程。這個方法接收的參數為:類型,子產品名以及應用程式的虛拟路徑,這些都将被asp.net用于建立appdomain,接着會啟動
指定虛拟目錄的asp.net程式。httpruntime的根對象将會在一個新的appdomain裡建立。每一個虛拟目錄或者asp.net程式将寄
宿在屬于自己的appdomain裡。它們僅僅在有請求到達時啟動。isapi擴充管理這些httpruntime對象的執行個體,然後基于請求的虛拟路徑,
把請求路由到正确的應用程式裡。
建立應用程式域并執行個體化了宿主環境之後,asp.net将建立并初始化核心對象(如httpcontext、httprequest和
httprespone)。httpcontext類包含特定于目前應用程式請求的對象,如httprequest和httprespone對象。
httprequest對象包含有關目前請求的資訊,包括cookie和浏覽器資訊。httprespone對象包含發送到用戶端的響應,包括所有呈現的
其實,一旦運作時啟動并運作起來,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()方法調用的
一部分。
說明:每一個請求都将被路由到一個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輸出,最後釋放該執行個體。