[翻譯]瞭解ASP.NET底層架構(四)

[翻譯]瞭解ASP.NET底層架構(四)
導讀:
  進入.NET運行時
  進入.NET運行時的真正的入口發生在一些沒有被文檔記載的類和接口中(譯著:當然,你可以用Reflector來查看J).除了微軟,很少人知道這些接口,微軟的傢伙們也並不熱衷於談論這些細節,他們認爲這些實現細節對於使用ASP.NET開發應用的開發人員並沒有什麼用處.
  工作進程(IIS5中是ASPNET_WP.EXE,IIS6中是W3WP.EXE)寄宿.NET運行時和ISAPI DLL,它(工作進程)通過調用COM對象的一個小的非託管接口最終將調用發送到ISAPIRuntime類的一個實例上(譯註:原文爲an instance subclass of the ISAPIRuntime class,但是ISAPIRuntime類是一個sealed類,疑爲作者筆誤,或者這裏的subclass並不是子類的意思).進入運行時的第一個入口就是這個沒有被文檔記載的類,這個類實現了IISAPIRuntime接口(對於調用者說明來說,這個接口是一個COM接口)這個基於Iunknown的底層COM接口是從ISAPI擴展到ASP.NET的一個預定的接口.圖3展示了IISAPIRuntime接口和它的調用簽名.(使用了Lutz Roeder出色的.NET Reflector工具http://www.aisto.com/roeder/dotnet/).這是一個探索這個步步爲營過程的很好的方法.
     
  圖3-如果你想深入這個接口,打開Reflector,指向System.Web.Hosting命名空間. ISAPI DLL通過調用一個託管的COM接口來打開進入ASP.NET的入口,ASP.NET接收一個指向ISAPI ECB的非託管指針.這個ECB包含訪問完整的ISAPI接口的能力,用來接收請求和發送響應回到IIS.
  IISAPIRuntime接口作爲從ISAPI擴展來的非託管代碼和ASP.NET之間的接口點(IIS6中直接相接,IIS5中通過命名管道).如果你看一下這個類的內部,你會找到含有以下簽名的ProcessRequest函數:
  [return: MarshalAs(UnmanagedType.I4)]intProcessRequest([In] IntPtr ecb, [In, MarshalAs(UnmanagedType.I4)] intuseProcessModel);
  其中的ecb參數就是ISAPI擴展控制塊(Extention Control Block),被當作一個非託管資源傳遞給ProcessRequest函數.這個函數接過ECB後就把它做爲基本的輸入輸出接口,和Request和Response對象一起使用.ISAPI ECB包含有所有底層的請求信息,如服務器變量,用於表單(form)變量的輸入流和用於回寫數據到客戶端的輸出流.這一個ecb引用基本上提供了用來訪問ISAPI請求所能訪問的資源的全部功能,ProcessRequest是這個資源(ecb)最初接觸到託管代碼的入口和出口.
  ISAPI擴展異步地處理請求.在這個模式下ISAPI擴展馬上將調用返回到工作進程或者IIS線程上,但是在當前請求的生命週期上ECB會保持可用.ECB含有使ISAPI知道請求已經被處理完的機制(通過ecb.ServerSupportFunction方法)(譯註:更多信息,可以參考開發ISAPI擴展的文章),這使得ECB被釋放.這個異步的處理方法可以馬上釋放ISAPI工作線程,並將處理傳遞到由ASP.NET管理的一個單獨的線程上.
  ASP.NET接收到ecb引用並在內部使用它來接收當前請求的信息,如服務器變量,POST的數據,同樣它也返回信息給服務器.ecb在請求完成前或超時時間到之前都保持可訪問(stay alive),這樣ASP.NET就可以繼續和它通訊直到請求處理完成.輸出被寫入ISAPI輸出流(使用ecb.WriteClient())然後請求就完成了,ISAPI擴展得到請求處理完成的通知並釋放ECB.這個實現是非常高效的,因爲.NET類本質上只是對高效的、非託管的ISAPI ECB的一個非常”瘦”(thin)的包裝器.
  裝載.NET-有點神祕
  讓我們從這兒往回退一步:我跳過了.NET運行時是怎麼被載入的.這是事情變得有一點模糊的地方.我沒有在這個過程中找到任何的文檔,而且因爲我們在討論本機代碼,沒有很好的辦法來反編譯ISAPI DLL並找出它(裝載.NET運行時的代碼)來.
  我能作出的最好的猜測是當ISAPI擴展接受到第一個映射到ASP.NET的擴展名的請求時,工作進程裝載了.NET運行時.一旦運行時存在,非託管代碼就可以爲指定的虛擬目錄請求一個ISAPIRuntime的實例(如果這個實例還不存在的話).每個虛擬目錄擁有它自己的應用程序域(AppDomain),當一個獨立的應用(指一個ASP.NET程序)開始的時候ISAPIRuntime從啓動過程就一直在應用程序域中存在.實例化(譯註:應該是指ISAPIRuntime的實例化)似乎是通過COM來進行的,因爲接口方法都被暴露爲COM可調用的方法.
  當第一個針對某虛擬目錄的請求到來時,System.Web.Hosting.AppDomainFactory.Create()函數被調用來創建一個ISAPIRuntime的實例.這就開始了這個應用的啓動進程.這個調用接收這個應用的類型,模塊名稱和虛擬目錄信息,這些信息被ASP.NET用來創建應用程序域並啓動此虛擬目錄的ASP.NET程序.這個HttpRuntime實例(譯註:原文爲This HttpRuntime derived object,但HttpRuntime是一個sealed類,疑爲原文錯誤)在一個新的應用程序域中被創建.每個虛擬目錄(即一個ASP.NET應用程序寄)宿在一個獨立的應用程序域中,而且他們也只有在特定的ASP.NET程序被請求到的時候纔會被載入.ISAPI擴展管理這些HttpRuntime對象的實例,並根據請求的虛擬目錄將內部的請求路由到正確的那個HttpRuntime對象上.
  
  
  圖4-ISAPI請求使用一些沒有文檔記載的類,接口並調用許多工廠方法傳送到ASP.NET的HTTP管道的過程.每個Web程序/虛擬目錄在它自己的應用程序域中運行,調用者(譯註:指ISAPI DLL)保持一個IISAPIRuntime接口的引用來觸發ASP.NET的請求處理.
  

本文轉自
http://www.cnblogs.com/tmfc/archive/2006/08/31/491663.html
標籤詞:
ASP ISAPI 託管代碼 實例化 虛擬目錄 ECB Iunknown 接口方法 NET開發 DLL 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章