熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

從.NET類庫代碼來看ASP.NET運行時[1]

2013-11-13 11:09:50  來源: .NET編程 
    寫在前面的話網上講Aspnet運行模式的好文章已經很多了筆者本不用多此一舉另成一文但從筆者自己的學習經驗看如果學到的這些知識不能對應到類庫中的源代碼印象總歸不夠深刻大有隔靴搔癢之感只好自己寫上一篇對這方面的知識做個小小的總結文中所有內容都是筆者在看了網上很多文章後結合自己的開發經驗得出的一些理解難免有錯誤的地方歡迎批評指出另外由於筆者能力所限很多地方並未說透(真正對應到代碼)也盼高手能夠給予補充

  進入Aspnet運行時之前

  雖然本文的重點是對托管代碼的解析但為了整個知識點的完整性這裡簡單介紹一下IIS處理請求的一些基本情況在一個IIS服務器上你可以設置多個應用程序池(每個應用程序池可以單獨設置允許使用的最大內存數量CPU使用率回收工作進程的時間間隔等參數而且一個應用程序池裡面只能使用一個版本的NET Framework)然後把自己的Web應用分別部署到這些應用程序池中在默認情況下每個應用池會有一個工作進程wwpexe來維護(如果開通了Web園功能也可以設置多個工作進程)每個應用程序(虛擬目錄)在池中都有自己的應用程序域這些應用程序域都處於這個應用程序池的工作進程的進程空間內

  IIS是通過各種ISAPI的擴展來處理各種類型的應用的當我們從客戶端提交一個請求過來之後IIS會根據請求的頁面或者服務的類型把請求映射到指定的ISAPI擴展比方說如果我們需要讓IIS支持perl這樣的服務器端程序(當然這個移植工作早就有人做過了)我們就需要編寫一個專門處理對perl頁面進行的請求的ISAPI擴展根據ISAPI的定義(符合這個定義的ISAPI擴展才能和IIS正常交互)在你的擴展中可以包括ISAPI Extension和ISAPI Filter兩大部分ISAPI Extension是對請求的處理程序完成和web服務器之間的輸入輸出而ISAPI Filter則是一些回調接口你可以通過實現這些接口來介入到整個請求處理的每一步驟對AuthenticationRevolveCache等環節進行控制另外ISAPI本身就是在工作進程裡運行的而aspnet運行時也是在工作進程裡運行的所以兩者的交互非常有效率

  對於aspx頁面這個擴展就是aspnet_isapidll因為這些ISAPI都是非托管的Win應用直接對它們進行改動是比較困難的所以為了增強Aspnet運行時的可擴展性aspnet_isapidll本身的功能非常少我們可以把aspnet_isapidll簡單理解為請求信息的路由器負責把請求從IIS傳送到aspnet運行時而後面我們將要講到的HttpHandle和HttpModule則分別擔負起了ISAPI Extension和ISAPI Filter的功能幸運的是HttpHandle和HttpModule可以由純的托管代碼來實現

  從非托管代碼到托管代碼

  前面說了aspnet_isapidll是非托管代碼而aspnet運行時是托管代碼他們都運行在wwpexe工作進程裡面那麼兩者之間的調用點發生在什麼地方呢?在介紹接下來的內容之前必須先介紹一個概念ECBECB的全稱是Extension Control Block它是一個非托管資源包具有對ISAPI接口完整的訪問能力包含了所有和一個傳入請求有關的底層信息如提交的標單中的數據等等所以說aspnet中的托管代碼想要訪問aspnet_isapidll對外提供的接口就需要通過ECB其實更准確的來說是托管代碼公布了一個IUnknown類型的接口供aspnet_isapidll調用而aspnet_isapidll在調用的時候會把自己的ecb地址傳進去

  明白了ECB的概念下面我們要介紹一個接口和一個接口的實現類(位於SystemWebHosting名字空間下)請讀者注意筆者在代碼中的注釋(本文的主要目的就是和大家一起從代碼實現的角度來認識整個Aspnet運行時所以代碼裡的注釋是筆者添加的關鍵性說明後面的所有代碼段都是這樣)

/**//*InterfaceType(ComInterfaceTypeInterfaceIsIUnknown)指明了這個接口將作為 IUnknown 派生接口向 COM 公開這就使得isapidll可以以COM方式調用此接口*/
[ComImport Guid(acfccabeaad) InterfaceType(ComInterfaceTypeInterfaceIsIUnknown)]
public interface IISAPIRuntime
{
void StartProcessing();
void StopProcessing();
/**//*ProcessRequest方法就是整個處理流程中托管代碼和非托管代碼的分界點可以看到裡面是以一個IntPtr結構傳入了調用方(也就是isapidll)的ECB地址*/
[return: MarshalAs(UnmanagedTypeI)]
int ProcessRequest([In] IntPtr ecb [In MarshalAs(UnmanagedTypeI)] int useProcessModel);
void DoGCCollect();
}

/**//*這個類實現了IISAPIRuntime接口它的實例對象存在於每一個AppDomain中作為整個Aspnet運行時的入口*/
public sealed class ISAPIRuntime : MarshalByRefObject IISAPIRuntime IRegisteredObject
{
// Fields
private static int _isThisAppDomainRemovedFromUnmanagedTable;
private static string s_thisAppDomainsIsapiAppId;

// Methods
[AspNetHostingPermission(SecurityActionDemand Level=AspNetHostingPermissionLevelMinimal) SecurityPermission(SecurityActionDemand Unrestricted=true)]
public ISAPIRuntime();
public void DoGCCollect();
public override object InitializeLifetimeService();
/**//*處理請求的入口點方法由isapidll以COM方式調用*/
public int ProcessRequest(IntPtr ecb int iWRType);
internal static void RemoveThisAppDomainFromUnmanagedTable();
internal void SetThisAppDomainsIsapiAppId(string appId);
public void StartProcessing();
public void StopProcessing();
void IRegisteredObjectStop(bool immediate);
}
  所以一切都是從aspnet_isapidll以COM方式調用了一個ISAPIRuntime對象的ProcessRequest方法開始的可以多提一句的是這種調用是異步的也就是說aspnet_isapidll在調用後會立即返回但ECB會一直保留下來直到整個請求被處理完畢之後再釋放

[]  []  []  []  


From:http://tw.wingwit.com/Article/program/net/201311/15294.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.