ASP.NET是什麼?
==============
ASP.NET是一個複雜的使用Managed 程式碼來從頭到尾處理Web請求的引擎.
整個ASP.NET引擎是完全建立在Managed 程式碼上的,所有的擴充功能也是通過Managed 程式碼的擴充來提供的.
ISAPI是什麼?
==============
ISAPI是一個底層的,非託管的,Win32風格的API. ISAPI的spec很簡單, 是為了效能而最佳化過的. 他們非常底層- 為處理回呼函數而去處理原始的指標和函數指標的列表, 但是他們提供了最底層的和面向效能效率的介面, 通過這些介面, 開發人員和工具供應商可以將他們的程式跟IIS掛接起來. 因為ISAPI非常底層所以它並不適合來開發應用級的代碼,而且ISAPI主要被傾向於用於橋接介面, 即向上層工具提供應用伺服器類型的功能.
例如,ASP和ASP.NET都是建立在ISAPI上的, Cold Fusion也一樣. 多數運行在IIS上的Perl, PHP 和JSP的實現也是如此.
ISAPI是一個傑出的工具,可以為上層應用提供高效的管道一樣的介面,這樣上層應用可以抽象出ISAPI提供的資訊.在ASP和ASP.NET中,將ISAPI介面提供的資訊抽象成了類型Request和Response這樣的對象,通過它們來讀取ISAPI請求中對應的資訊. 對ASP.NET來說,ISAPI dll的功能非常的”窮瘦”的, 只是作為一個將原始的請求轉寄到ASP.NET運行時的路由機制. 所有沉重的負擔和處理, 甚至請求的線程的處理都是由ASP.NET引擎還有你自己的代碼來處理的.
ISAPI跟ASP.NET之間是什麼關係?
===============
事實上,ASP.NET在微軟的平台上就是通過ISAPI擴充來和IIS進行互動的,這個擴充寄宿著.NET運行時和ASP.NET運行時.ISAPI提供了核心的介面,ASP.NET使用非託管的ISAPI代碼通過這個介面來從Web伺服器擷取請求,並發送響應回用戶端.ISAPI提供的內容可以通過通用對象(例如HttpRequest和HttpResponse)來擷取,這些對象通過一個定義良好並有很好訪問性的介面來暴露非管理的資料.
ISAPI Extension和ISAPI Filter是什麼?
===============
ISAPI extension和ISAPI filter就像是ISAPI支援的兩種協議.
ISAPI Extension是一個處理請求的介面, 提供對Web伺服器的輸入輸出的處理邏輯. 本質上來說是一個互動介面. ASP和ASP.NET就是作為Extension實現的.
ISAPI filter是提供一些功能的鉤子介面, 功能包括允許查看每一個到達IIS的請求, 然後修改某些功能的內容或者功能的行為, Authentication就是這樣的功能.
順便說一句, ASP.NET通過兩個概念來映射ISAPI式的功能:Http Handlers (extensions) 和Http Modules (filters)
WEB請求是如何從瀏覽器到ASP.NET的?
===============
1. 使用者從瀏覽器發出請求. 方式可以是: a. 輸入URL; b. 點擊超連結 c. 提交HTML表單 d.調用基於ASP.NET的web service
2. WEB伺服器的IIS獲得這個請求, 查看請求檔案的副檔名.
3. IIS根據自己的Application Extension(即script map)中的配置, 將ASP.NET註冊了的副檔名的請求發送給ASP.NET的ISAPI DLL-- aspnet_isapi.dll.
4. ASP.NET根據得到的請求的副檔名, 再一次對請求進行分配, 分配的目的地是請求對應的HTTP handler.
什麼是HTTP handler?
===============
每一個Http handler都是一個.net的類, 他們處理某一種檔案的副檔名. 其內部的行為可以簡單和可以非常複雜.
能不能總結一下IIS和ASP.NET憑請求中的什麼資訊來完成尋找正確處理的呢?
===============
副檔名. IIS根據副檔名找到ASP.NET, ASP.NET根據副檔名找到Http handler.
既然IIS和ASP.NET都通過副檔名來進行對請求的路由, 那麼我如何才能完成添加這些副檔名的配置呢?
===============
你不應該設定手動這些副檔名.使用aspnet_regiis.exe這個工具來確保所有的映射都被正確的設定.
cd <.NetFrameworkDirectory>
aspnet_regiis – i
這個命令將為整個Web網站註冊特定版本的ASP.NET運行時,包括指令碼 (副檔名) 映射和用戶端指令碼庫(包括進行控制項驗證的代碼等).注意它註冊的是<.NetFrameworkDirectory>中安裝的特定版本的CLR(如1.1,2.0).aspnet_regiis的選項令您可以對不同的虛擬目錄進行配置.每個版本的.NET架構都有自己不同版本的aspnet_regiis工具,你需要運行對應版本的aspnet_regiis來為web網站或者虛擬目錄來配置指定版本的.NET framework. 從ASP.NET2.0開始提供了ASP.NET配置頁面,可以通過這個頁面在IIS管理主控台來互動的配置.NET版本.
IIS6的應用程式集區是什麼?
==============
Application Pool是IIS6建立的單獨的工作者進程, 包括ISAPI動態連結程式庫的執行在內的所有的處理都在這個進程內發生.
應用程式集區有啥好處呀?
==============
應用程式集區是IIS6的重大改進, 它在什麼東西可以放在一個進程中啟動並執行問題上有更細緻的控制. 從虛擬目錄到整個網站都可以進行應用程式集區的設定, 這樣, 你就可以將每一個web應用程式隔離到他們自己的進程中, 與其他同一機器上正在啟動並執行web應用程式完全無關. 一個崩潰了, 其他的照樣運行.
應用程式集區提供高度的可設定性.
更容易被監測和管理.
最佳化了效能. 因為應用程式集區直接跟核心態的HTTP.sys驅動程式互動, 所以對於http操作的效能更高.
應用程式集區對ASP.NET有一些內部的瞭解和支援, ASP.NET可以使用應用程式集區的底層API, 這些API可以將緩衝的重擔從ASP.NET層直接轉移到web Server的緩衝上.
ISAPI extension運行在應用程式集區中, .NET runtime也運行在同樣的進程中, 所以ISAPI和.NET運行時的通訊就屬於進程內通訊, 當然比IIS5的具名管道通訊更加高效了.
請求進入ASP.NET的第一個函數入口是什麼?
===============
ISAPIRuntime.ProcessRequest()
調用是如何走到ISAPIRuntime.ProcessRequest()中的呢? 進入之後有做了哪些事情呢?
===============
w3wp.exe中寄宿著.NET運行時.
ISAPI.DLL會通過低級COM對象去調用一小部分非託管介面, 這些底層的COM最終將調用到ISAPIRuntime類的一個執行個體上.
ASP.NET的System.Web.Hosting命名空間下有個介面, 叫做IISAPIRuntime. 這是一個通過COM暴露給調用者的介面. 使用這個介面的COM專門用來完成從ISAPI Extension向ASP.NET組件調用的功能. 也就是說, IISAPIRuntime介面是Unmanaged 程式碼進入Managed 程式碼的存取點.
介面中ProcessRequest方法的簽名如下:
[return: MarshalAs(UnmanagedType.I4)]
int ProcessRequest([In] IntPtr ecb,
[In, MarshalAs(UnmanagedType.I4)] int useProcessModel);
注意這裡的ecb參數, 它是ISAPI Extension Control Block的縮寫, 是作為一種非託管資源傳遞給ProcessRequest方法的. ProcessRequest方法使用ecb作為Request和Reponse對象使用的基本的輸入輸出對象. ecb中含有瀏覽器發送來的請求的所有底層資訊, 包括伺服器變數, 輸入資料流和要被寫回到client端的輸出資料流. 單單一個ecb的引用基本上就提供了訪問ISAPI請求的所有功能. ProcessRequest是ecb與Managed 程式碼打交道的入口, 也是出口. 即ProcessRequest方法一旦結束, ASP.NET的處理也就結束了.
ISAPI extension是非同步運行請求的. 也就是說, ISAPI extension(比如ASP.NET)會立即返回到調用它的的工作者進程(w3wp.exe)或者IIS線程中, 但是保持當前請求的ECB的存活狀態. ECB中包含讓ISAPI知曉請求的處理已經結束的機制(通過ecb.ServerSupportFunction) , 這個機制會在得到ECB的通知後釋放掉ECB. 這個非同步過程能迅速的釋放ISAPI工作者線程, 將處理任務轉交給ASP.NET管理的獨立線程.
ASP.NET收到ECB的引用之後, 就在內部使用它來擷取關於當前請求的資訊, 比如說伺服器變數, POST資料, 還有發送給伺服器的輸出資訊. ECB結構在請求處理結束之前都是存活的. 在timeout時, ecb會被銷毀. 只要ecb還在, 處理還沒結束, ASP.NET就會一直跟它打交道 輸出結果被寫入到ISAPI 輸出資料流(ecb.WriteClient())中. 當請求結束了, ISAPI extension 被通知到, 然後它就知道ECB可以釋放掉了. 這個過程非常高效, 因為.net的類基本上都是作為圍繞著高效能的, 非託管的ISAPI ECB的封裝者而行動的.