寫在前面的話
網上講Asp
net運行模式的好文章已經很多了
筆者本不用多此一舉
另成一文
但從筆者自己的學習經驗看
如果學到的這些知識不能對應到類庫中的源代碼
印象總歸不夠深刻
大有隔靴搔癢之感
只好自己寫上一篇
對這方面的知識做個小小的總結
文中所有內容都是筆者在看了網上很多文章後
結合自己的開發經驗得出的一些理解
難免有錯誤的地方
歡迎批評指出
另外
由於筆者能力所限
很多地方並未說透(真正對應到代碼)
也盼高手能夠給予補充
一進入Aspnet運行時之前 雖然本文的重點是對托管代碼的解析
但為了整個知識點的完整性
這裡簡單介紹一下IIS處理請求的一些基本情況
在一個IIS服務器上
你可以設置多個應用程序池(每個應用程序池可以單獨設置允許使用的最大內存數量
CPU使用率
回收工作進程的時間間隔等參數
而且一個應用程序池裡面只能使用一個版本的
NET Framework)
然後把自己的Web應用分別部署到這些應用程序池中
在默認情況下
每個應用池會有一個工作進程w
wp
exe來維護(如果開通了Web園功能
也可以設置多個工作進程)
每個應用程序(虛擬目錄)在池中都有自己的應用程序域
這些應用程序域都處於這個應用程序池的工作進程的進程空間內
IIS是通過各種ISAPI的擴展來處理各種類型的應用的
當我們從客戶端提交一個請求過來之後
IIS會根據請求的頁面或者服務的類型
把請求映射到指定的ISAPI擴展
比方說
如果我們需要讓IIS支持perl這樣的服務器端程序(當然
這個移植工作早就有人做過了)
我們就需要編寫一個專門處理對perl頁面進行的請求的ISAPI擴展
根據ISAPI的定義(符合這個定義的ISAPI擴展才能和IIS正常交互)
在你的擴展中可以包括ISAPI Extension和ISAPI Filter兩大部分
ISAPI Extension是對請求的處理程序
完成和web服務器之間的輸入輸出
而ISAPI Filter則是一些回調接口
你可以通過實現這些接口來介入到整個請求處理的每一步驟
對Authentication
RevolveCache等環節進行控制
另外
ISAPI本身就是在工作進程裡運行的
而asp
net運行時也是在工作進程裡運行的
所以兩者的交互非常有效率
對於
aspx頁面
這個擴展就是aspnet_isapi
dll
因為這些ISAPI都是非托管的Win
應用
直接對它們進行改動是比較困難的
所以
為了增強Asp
net運行時的可擴展性
aspnet_isapi
dll本身的功能非常少
我們可以把aspnet_isapi
dll簡單理解為請求信息的路由器
負責把請求從IIS傳送到asp
net運行時
而後面我們將要講到的HttpHandle和HttpModule則分別擔負起了ISAPI Extension和ISAPI Filter的功能
幸運的是
HttpHandle和HttpModule可以由純的托管代碼來實現
二從非托管代碼到托管代碼 前面說了
aspnet_isapi
dll是非托管代碼
而asp
net運行時是托管代碼
他們都運行在w
wp
exe工作進程裡面
那麼兩者之間的調用點發生在什麼地方呢?在介紹接下來的內容之前必須先介紹一個概念
ECB
ECB的全稱是Extension Control Block
它是一個非托管資源包
具有對ISAPI接口完整的訪問能力
包含了所有和一個傳入請求有關的底層信息
如提交的標單中的數據等等
所以說
asp
net中的托管代碼想要訪問aspnet_isapi
dll對外提供的接口
就需要通過ECB
其實更准確的來說
是托管代碼公布了一個IUnknown類型的接口供aspnet_isapi
dll調用
而aspnet_isapi
dll在調用的時候會把自己的ecb地址傳進去
明白了ECB的概念
下面我們要介紹一個接口和一個接口的實現類(位於System
Web
Hosting名字空間下)
請讀者注意筆者在代碼中的注釋(本文的主要目的就是和大家一起從代碼實現的角度來認識整個Asp
net運行時
所以代碼裡的注釋是筆者添加的關鍵性說明
後面的所有代碼段都是這樣)
/**//*InterfaceType(ComInterfaceType
InterfaceIsIUnknown)指明了這個接口將作為 IUnknown 派生接口向 COM 公開
這就使得isapi
dll可以以COM方式調用此接口
*/
[ComImport
Guid(
a
c
f
c
c
a
be
a
a
d
)
InterfaceType(ComInterfaceType
InterfaceIsIUnknown)]
public interface IISAPIRuntime
{
void StartProcessing();
void StopProcessing();
/**//*ProcessRequest方法就是整個處理流程中托管代碼和非托管代碼的分界點
可以看到裡面是以一個IntPtr結構傳入了調用方(也就是isapi
dll)的ECB地址*/
[return: MarshalAs(UnmanagedType
I
)]
int ProcessRequest([In] IntPtr ecb
[In
MarshalAs(UnmanagedType
I
)] int useProcessModel);
void DoGCCollect();
}
/**//*這個類實現了IISAPIRuntime接口
它的實例對象存在於每一個AppDomain中
作為整個Asp
net運行時的入口
*/
public sealed class ISAPIRuntime : MarshalByRefObject
IISAPIRuntime
IRegisteredObject
{
// Fields
private static int _isThisAppDomainRemovedFromUnmanagedTable;
private static string s_thisAppDomainsIsapiAppId;
// Methods
[AspNetHostingPermission(SecurityAction
Demand
Level=AspNetHostingPermissionLevel
Minimal)
SecurityPermission(SecurityAction
Demand
Unrestricted=true)]
public ISAPIRuntime();
public void DoGCCollect();
public override object InitializeLifetimeService();
/**//*處理請求的入口點方法
由isapi
dll以COM方式調用*/
public int ProcessRequest(IntPtr ecb
int iWRType);
internal static void RemoveThisAppDomainFromUnmanagedTable();
internal void SetThisAppDomainsIsapiAppId(string appId);
public void StartProcessing();
public void StopProcessing();
void IRegisteredObject
Stop(bool immediate);
}
所以
一切都是從aspnet_isapi
dll以COM方式調用了一個ISAPIRuntime對象的ProcessRequest方法開始的
可以多提一句的是
這種調用是異步的
也就是說
aspnet_isapi
dll在調用後會立即返回
但ECB會一直保留下來
直到整個請求被處理完畢之後再釋放
[] [] [] []
From:http://tw.wingwit.com/Article/program/net/201311/15294.html