使用 .NET Framework 開發 IIS 7.0 模組和處理常式
作者: Mike Volodarsky
概觀
本文著重于根據.NET Framework開發 IIS 7.0 和更新版本網頁伺服器功能。 本文示範:
- 如何決定是否要開發 IIS 模組或 IIS 處理常式
- 如何使用 Visual Studio、Visual C# Express 或命令列工具來設定開發環境,並提供.NET Framework
- 如何建立您的第一個專案
- 如何開發簡單的模組和處理常式
- 如何將簡單的模組和處理常式部署至 IIS 伺服器
若要查看一些真實世界的受管理 IIS 模組和處理常式,並為您的應用程式下載它們,請流覽 使用 HttpRedirection 模組將要求重新導向至您的應用程式、 使用 DirectoryListingModule 取得 IIS 網站的美觀目錄清單,以及 使用 IconHandler 在 ASP.NET 應用程式中顯示美觀的檔案圖示。
簡介:使用 ASP.NET 開發 IIS 功能
IIS 7.0 之前的 IIS 版本提供稱為 ISAPI 的 C API,作為建置 Web 服務器功能的主要擴充性 API。 IIS 7.0 和更新版本已從頭重新設計,以提供全新的 C++ API,其中所有現成功能都是以為基礎,以允許網頁伺服器的完整執行時間擴充性。
此外,IIS 第一次也提供完整逼真度 .NET API 來擴充 Web 服務器,方法是利用與 ASP.NET 2.0 緊密整合。 為此,這表示您現在可以使用以熟悉的 ASP.NET 2.0 API 建置的新網頁伺服器功能來擴充 IIS。 同樣地,您可以在 IIS 上使用現有的 ASP.NET 2.0 模組和處理常式,利用 ASP.NET 整合來增強應用程式的強大功能,而不需要撰寫任何新的程式碼。 若要深入瞭解 IIS 中的 ASP.NET 整合,請參閱 ASP.NET 與 IIS 7 整合。
交易的工具:決定您的開發環境
若要建置 IIS 模組和處理常式,請使用任何可讓您開發和編譯 .NET 元件的環境。 一些常見的選項包括:
- Visual Studio 2005。 或者,您也可以下載 Visual Studio 2008的最新 Beta 版本。
- Visual C# 2005 Express Edition、免費下載 (或其他 Express 工具,包括 Visual Basic 2005 Express) 。
- .NET Framework 執行時間 (隨附的C# 命令列編譯程式 (csc.exe) 適用于其他語言,您必須下載SDK) ,以及您慣用的來源編輯器。
本文中的範例會使用 C#,不過您可以開發任何其他支援的 .NET 語言 (IIS 元件,但 Managed C++) 除外。 本文說明如何使用上述三個環境來開發 IIS 擴充性元件。
注意
因為 IIS 會利用現有的 ASP.NET API 進行 .NET 擴充性,所以您可以在 Windows XP® 和 Windows Server® 2003 上使用 .NET Framework 2.0 開發 IIS .NET 模組和處理常式。 不過,如果您打算使用數個新的 ASP.NET API 之一來支援新的 IIS 功能,則必須在 Windows Vista 上開發,或從 Windows Vista® 取得 System.Web.dll 版本,或從最新版的 .NET Framework 3.5編譯器代碼。
擴充 IIS 的兩種方式:模組與處理常式
所有 IIS 網頁伺服器功能都符合兩種類別:模組和處理常式。
類似于舊版 IIS 中 ISAPI 篩選的 模組會參與每個要求的要求處理,以便以某種方式變更或新增至它。 IIS 中某些內建模組的範例包括驗證模組,可操作要求的驗證狀態、壓縮壓縮回應的壓縮模組,以及記錄要求記錄檔之要求相關資訊的模組。
模組是 .NET 類別,可實作 ASP.NET System.Web.IHttpModule 介面,並使用 System.Web 命名空間中的 API 參與一或多個 ASP。NET 的要求處理階段。
與舊版 IIS 中的 ISAPI 延伸模組類似的 處理常式 負責處理要求,並產生特定內容類型的回應。 模組和處理常式的主要差異在於處理常式通常會對應至特定的要求路徑或延伸模組,並支援處理該路徑或延伸模組對應到的特定伺服器資源。 IIS 提供的處理常式範例包括 ASP、處理 ASP 腳本、靜態檔案處理常式、提供靜態檔案和 ASP。NET 的 PageHandler 會處理 ASPX 頁面。
處理常式是實作 ASP.NET System.Web.IHttpHandler 或 System.Web.IHttpAsyncHandler介面的 .NET 類別,並使用System.Web命名空間中的 API 來產生其支援特定內容的 HTTP 回應。
規劃開發 IIS 功能時,您應該詢問的第一個問題是此功能是否負責提供特定 URL/延伸模組的要求,或根據任意規則套用至所有/部分要求。 在先前的案例中,您的 應該是處理常式,而後者則是模組。
本文示範如何建置簡單模組和簡單的處理常式、建立專案及編譯專案的常見步驟,以及部署至伺服器的特定步驟。
注意
如果您正在開發模組,則不需要開發處理常式,反之亦然。
消費者入門:建立 Visual Studio 專案
若要建置模組或處理常式,您必須產生 .NET 元件 (DLL) 包含模組/處理常式類別。 如果您使用 Visual Studio 或Visual Studio Express工具,第一個步驟是建立類別庫專案:
從 [檔案] 功能表中,選取 [新增]、[專案 ...]。 在 [新增專案] 對話方塊 (下方的 [) ],選取 [Visual C#] 專案類型,然後選取 Visual Studio 已安裝範本右側清單中的 [類別庫]。
我們必須新增 「System.Web.dll」 元件的參考,其中包含用來開發 ASP.NET 和 IIS 模組和處理常式的 API。 以滑鼠右鍵按一下右側方案總管樹狀檢視中 [專案] 節點底下的 [參考]節點,選擇 [新增參考...],然後在 [.NET] 索引標籤中選取 [System.Web 元件],版本 2.0 (下方) 。
注意
如果您不打算利用 IIS 特定的 ASP.NET API,您可以在 Windows XP 和 Windows Server 2003 上使用 System.Web 元件 2.0 版。 參考此元件的模組和處理常式可以在 Windows Vista 和 Windows Server 2008 上的 IIS 上部署及操作,而不會發生問題。 如果您想要在模組中使用幾個 IIS 特定 ASP.NET API,您必須在 Windows Vista、Windows Server 2008 上開發,或從 .NET Framework 3.5 取得System.Web.dll元件。 IIS 特定 API 包括 HttpServerUtility.TransferRequest、HttpResponse.Headers 集合、HttpApplication.LogRequest 事件,以及其他數個。
撰寫程式碼:建置簡單的模組
第一個工作是建置簡單的模組。 本文稍後也會建置範例處理常式。
若要建立 模組,請定義實作 System.Web.IHttpModule 介面的類別。
刪除專案系統所產生的 「class1.cs」 檔案,並以滑鼠右鍵按一下右側樹狀檢視中的 MyIIS7Project 專案,選取 [新增]、[ 新增專案]、選擇 [類別],然後在 [名稱] 欄位中輸入 「MyModule.cs」 來新增名為 MyModule 的新C# 類別。
匯入 System.Web 命名空間,以便我們可以輕鬆地存取其中的類型。
讓 MyModule 類別實作 IHttpModule 介面,並定義介面成員 Dispose () 和 Init () 。 以滑鼠右鍵按一下 [IHttpModule 介面],然後選擇 [實作介面] 選項,即可快速執行此動作:
Dispose () 方法的目的是在卸載模組時確定性地清除任何 Unmanaged 資源,因此可以在垃圾收集行程完成模組實例之前釋放資源。 您大部分時間可能會讓此方法保持空白。
Init (HttpApplication 內容) 方法是感興趣的主要方法。 其角色是執行模組的初始化,並將模組連線至 HttpApplication 類別上可用的一或多個要求處理事件。 在要求處理期間,系統會針對其訂閱的每個事件叫用模組,以允許它執行和執行其服務。 若要這樣做:
藉由將模組類別上的方法連接到提供的 HttpApplication 實例上的其中一個事件,以訂閱一或多個要求處理事件。 方法必須遵循 System.EventHandler 委派簽章。 我們會定義名為 OnPreExecuteRequestHandler的新方法,並將它連線到 HttpApplication。PreRequestRequestHandlerExecute 事件,會在伺服器即將叫用要求的要求處理常式之前發生:
public void Init(HttpApplication context) { context.PreRequestHandlerExecute += newEventHandler(OnPreRequestHandlerExecute) }
此時,我們的模組會設定為在每個要求上接收 PreRequestHandlerExecute 事件。 您可以針對您想要接收的其他所有事件重複此動作。
現在,我們的模組會執行一些有用的動作,說明如何使用模組可使用的一些 ASP.NET API。 檢查要求是否指定查閱者標頭,如果是,請拒絕該標頭,這是防止人員從其他網站連結至您的網站的十分好方法。 我們將在 OnPreRequestHandlerExecute 方法中執行此動作,在處理常式在每個要求上執行之前叫用:
public void OnPreRequestHandlerExecute ( Object source, EventArgs e) { HttpApplication app = (HttpApplication)source; HttpRequest request = app.Context.Request; if (!String.IsNullOrEmpty( request.Headers["Referer"] )) { throw new HttpException(403, "Uh-uh!"); } }
注意
HttpApplication 實例會透過 來源 引數提供給模組,而且需要轉換。 您可以從 HttpApplication 實例存取其餘的要求物件模型,例如 HttpCoNtext 物件,以及代表要求的自主 HttpRequest 物件。
上述程式碼會檢查是否已指定「查閱者」標頭,如果是,則會拒絕要求,並顯示 403 未經授權錯誤碼。
撰寫程式碼:建置簡單的處理常式
下一個工作是建置簡單的處理常式。 稍早在本文中,我們建置了範例模組 - 如果您想要改為閱讀建置模組的相關資訊,請返回 。
若要建立 處理常式,我們必須定義實作 System.Web.IHttpHandler 介面的類別, (如果我們想要讓頁面以非同步方式執行) ,也可以實作 System.Web.IHttpAsyncHandler 。 若要這樣做:
如果您尚未這麼做,請刪除專案系統所產生的 「class1.cs」 檔案,然後在 [名稱] 欄位中以滑鼠右鍵按一下 MyIIS7Project 專案中的 MyIIS7Project 專案,然後選取 [新增]、[ 新增專案]、選擇 [類別],然後在 [名稱] 欄位中輸入 「MyHandler.cs」 來新增名為 MyHandler.cs的新 C# 類別。
匯入 System.Web 命名空間,以便我們可以輕鬆地存取其中的類型。
讓 MyHandler 類別實作 IHttpHandler 介面,並定義 介面成員 IsReusable 和 ProcessRequest () 。 您可以用滑鼠右鍵按一下 [IHttpHandler 介面],然後選擇 [實作介面] 選項,以快速執行此動作:
IsReusable () 會指出您的處理常式實例是否可用於後續要求。 在某些情況下,處理要求之後,處理常式可能處於不正確的狀態來處理另一個要求,特別是如果您已將先前要求的相關資料儲存在成員變數中。 請注意,執行時間永遠不會使用相同的處理常式實例同時處理兩個要求,即使其標示為可重複使用也一樣。 如果您的處理常式未將任何每個要求狀態儲存在成員變數中,而且可以視需要呼叫其 ProcessRequest 函式,請讓此屬性傳回 true 以允許重複使用。
ProcessRequest () 方法是處理常式的主要進入點。 其角色是處理 HttpRequest 實例所指定的要求,可從提供的 HttpCoNtext 實例取得,並使用 HttpResponse 實例也可以從 HttpCoNtext 取得適當的回應。 在 ExecuteRequestHandler 要求處理階段期間,執行時間會叫用 ProcessRequest () 方法,而且只有在根據設定的處理常式對應至處理常式的要求時才叫用。 這與接收應用程式所有要求的通知模組不同。
請先實作 IsReusable 屬性。 由於我們的處理常式不會儲存要求的任何成員狀態,而且能夠支援對具有不同要求之 ProcessRequest () 的多個呼叫,因此我們會將它標示為可重複使用,方法是傳回 true。
public bool IsReusable { get { return true; }
最後,讓我們實作 ProcessRequest () 方法,讓處理常式實際執行有用的動作。 為了保持良好且簡單,我們的處理常式會傳回伺服器上的目前時間,選擇性地允許在查詢字串中指定時區。 我們的目標是能夠要求 URL,例如
http://myserver/time.tm
,並取得伺服器上的目前時間。 此外,我們將能夠藉由要求http://myserver/time.tm?utc=true
來取得通用協調時間。 以下是我們的實作:public void ProcessRequest(HttpContext context) { DateTime dt; String useUtc = context.Request.QueryString["utc"]; if (!String.IsNullOrEmpty(useUtc) && useUtc.Equals("true")) { dt = DateTime.UtcNow; } else { dt = DateTime.Now; } context.Response.Write( String.Format( "<h1>{0}</h1>", dt.ToLongTimeString() ) ); }
我們使用 HttpRequest.QueryString 集合來擷取 QueryString 變數,並使用 HttpResponse.Write 方法寫入目前時間以回應。 這只是您在處理常式中選擇執行之專案的範例 - HttpRequest 類別提供要求的詳細資訊,而 HttpResponse 類別提供許多不同方式來塑造傳回給用戶端的回應。
處理常式已完成。
程式碼完成:編譯模組/處理常式
既然我們已實作模組和處理常式,我們可以將它們編譯成可在執行時間載入 ASP.NET 的元件。 如果您使用 Visual Studio 或Visual Studio Express,請按 [Ctrl-Shift-B] 或以滑鼠右鍵按一下專案並選擇 [建置],直接從工具編譯專案。
.DLL元件將會在 < ProjectDirectory > \bin\debug 資料夾中產生,以及 。您可以在專案的偵錯階段期間,用來對伺服器上的元件進行偵錯的 PDB 符號檔/包括例外狀況中的源程式碼。
如果您要將元件上傳至生產伺服器,請務必以滑鼠右鍵按一下方案節點、選擇 [Configuration Manager],並將類型變更為 [偵錯],將 [方案組態] 變更為 [發行]。 上傳元件的 Release 版本 (讓 PDB 檔案保留) - 這會從元件中移除偵錯資訊,並將它優化以加快程式碼的速度。
如果您未使用 Visual Studio,請使用 Framework 執行時間中包含的 C# 命令列編譯器編譯專案。 若要編譯專案,請開啟命令列提示字元 (如果您位於 Windows Vista 或 Windows Server 2008) ,請務必使用 [以系統管理員身分執行] 選項來執行命令列提示字元:
> %windir%\Microsoft.NET\Framework\v2.0.50727\csc.exe /t:library /out:MyIIS7Project.dll /debug \*.cs /r:System.Web.dll
這會產生 MyIIS7Project.DLL 和 MyIIS7Project.PDB 檔案。 如果您想要建置元件的發行版本本,請省略 /debug 參數,並包含 /o 參數以優化元件。
將元件部署至伺服器
既然我們已實作自訂模組和處理常式,我們會將它們部署至 Web 應用程式。 有數種方式可將模組或處理常式部署至應用程式,以及一些您可以用來量身打造其部署所需的組態選項。 我們說明下列最基本的部署步驟。 如需部署和設定選項的進階討論,包括如何部署整個伺服器的模組/處理常式,請參閱系列中的下一篇文章:即將推出) 部署 IIS 模組和 (處理常式。
下列步驟假設您要將模組和處理常式部署到 IIS 伺服器上的現有應用程式。 如果您沒有建立應用程式,請使用通常位於 %systemdrive%\inetpub\wwwroot
的「預設網站」根應用程式。 在下列範例中,我們會將模組和處理常式部署到預設網站中名為 「myiis7project」 的應用程式。
若要部署模組和處理常式,請先讓元件包含其實作可供 ASP.NET 應用程式使用:
將稍早編譯 MyIIS7Project.dll 元件複製到位於應用程式的根目錄中的 /BIN 目錄。 如果此目錄不存在,請加以建立。
設定要載入應用程式中的模組和處理常式。 透過 [開始] 功能表開啟 IIS7 管理工具 ,在 [開始/搜尋] 方塊中輸入 inetmgr.exe ,然後按 Enter 鍵。 在工具中,按兩下左側樹狀檢視中的伺服器節點,然後展開 [站台] 節點,然後按兩下您要新增模組和處理常式的網站或應用程式。
選取 [模組] 功能圖示,然後按一下 [新增受控模組...] 動作,然後在產生的對話方塊中,輸入模組名稱 (任意) 和完整模組類型 「MyIIS7Modules.MyModule」。 請注意,您也可以在下拉式方塊中選取類型,因為此工具會自動在 bin 中載入元件,並探索實作 IHttpModule 介面的類型。 按 [確定] 以新增模組。
再次按兩下月臺/應用程式節點,然後選取 [處理常式對應] 功能圖示,以新增處理常式。 然後,按一下 [新增 Managed 處理常式] 動作,然後在產生的對話方塊中指定路徑 「time.tm」、類型為 「MyIIS7Modules.MyHandler」 指定 「MyHandler」,並針對名稱指定 「MyHandler」 (任意) 。 同樣地,請注意,類型會出現在下拉式方塊中,因為管理員工具會自動在您的元件中偵測到此類型。 按 [確定] 以新增處理常式。
上述動作所產生的應用程式組態會將 MyModule 模組設定為載入您的應用程式 (,以便針對所有要求) 執行,並將 MyHandler 處理常式對應至應用程式內 time.tm URL 的要求。
請注意,此設定可讓您的模組和應用程式只在 IIS 整合模式應用程式中執行。 如果您想要模組和處理常式也在 IIS 的傳統模式應用程式中執行,以及在舊版 IIS 上執行,您也必須新增模組和處理常式的傳統 ASP.NET 組態。 此外,在 IIS 或舊版 IIS 上以傳統模式執行時,您的處理常式會要求您建立腳本對應,將 .tm 延伸模組對應至 IIS scriptmaps 中的 ASP.NET,而您的模組只會針對對應至 ASP.NET 的延伸模組執行。 如需詳細資訊,請參閱 部署 IIS 模組和處理常式 (即將推出) 。
您也可以使用 IIS 命令列工具、 AppCmd.exe或從腳本或 Managed 程式碼操作 IIS 組態,或直接將組態放入 web.config 檔案,來新增模組和處理常式。 這些額外的選項會在部署 IIS 模組和處理常式中深入討論, (即將推出) 。
測試模組和處理常式
我們已部署並設定模組/處理常式。 現在要測試它們:
在應用程式中對 「time.tm」 提出要求,以測試處理常式。 如果成功,我們會在伺服器上看到目前的時間。 向您的應用程式提出要求,例如
http://localhost/myiis7project/time.tm
,我們在預設網站中將處理常式部署至 myiis7project 應用程式:如果處理常式已正確部署至此應用程式,您會在伺服器上看到目前的時間:
也請嘗試要求
http://localhost/myiis7project/time.tm?utc=true
以 UTC 顯示時間。測試模組。 在應用程式中建立名為 page.html 的簡單 HTML 頁面,連結至 /time.tm URL:
page.html
<html> <body> <a href="time.tm">View current server time</a> </body> </html>
然後,要求
http://localhost/myiis7project/page.html
顯示連結。 當您按一下連結時,您會看到錯誤:您可能會詢問我們是否只要求上述相同的 URL,並成功查看時間。 這是因為我們的模組已設定為拒絕應用程式的要求,以指定參考者標頭,每當使用者按一下連結以移至您的網站,而不是直接在瀏覽器中輸入 URL 時,瀏覽器就會新增此標頭。 因此,當您直接要求 URL 時,就能夠存取該 URL- 不過,當您遵循另一個頁面的連結時,您的要求會遭到我們的模組拒絕。
總結
在本文中,我們說明使用熟悉的 ASP.NET API 開發 IIS 模組和處理常式的基本步驟,並將其部署至您的應用程式。 我們也討論您對於開發環境的選項,以及如何決定何時要建置模組與處理常式。 本文中的資訊應該可讓您建置第一個模組和處理常式,以強化 IIS 應用程式的能力。
您也可以檢閱範例模組,以針對 ASP 啟用基本驗證。使用 .NET 開發模組中的 NET 成員資格提供者。
請務必查看 Managed IIS 模組和處理常式如何為您的應用程式增加價值,並流覽 使用 HttpRedirection 模組將要求重新導向至您的應用程式、 取得 IIS 網站的美觀目錄清單與 DirectoryListingModule,以及 使用 IconHandler 在 ASP.NET 應用程式中顯示美觀的檔案圖示,以查看應用程式的更多範例。