程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF技術剖析之四:基於IIS的WCF服務寄宿(Hosting)實現揭秘

WCF技術剖析之四:基於IIS的WCF服務寄宿(Hosting)實現揭秘

編輯:關於.NET

通過《再談IIS與ASP.NET管道》的介紹,相信讀者已經對IIS和ASP.NET的請求處理管道有了一個大致的了解,在此基礎上去理解基於IIS服務寄宿的實現機制就顯得相對容易了。概括地說,基於IIS的服務寄宿依賴於兩個重要的對象:System.ServiceModel.Activation.HttpModule和System. ServiceModel.Activation.HttpHandler。

一、通過HttpModule實現服務寄宿

在默認的情況下,基於IIS的服務寄宿是通過一個特殊的HttpModule實現的,其類型為System.ServiceModel.Activation.HttpModule,是一個定義在System.ServiceModel程序集中的內部類型。HttpModule的定義大體上如下面的代碼所示,我們很清楚地看到其實現的原理:將實現WCF Service請求處理的邏輯注冊到HttpApplication的PostAuthenticationRequest事件中。

   1: internal class HttpModule : IHttpModule
2: {
3: //其他成員
4: public void Init(HttpApplication context)
5: {
6: context.PostAuthenticateRequest += new EventHandler(HttpModule.ProcessRequest);
7: }
8: private static void ProcessRequest(object sender, EventArgs e)
9: {
10: //服務請求處理實現
11: }
12: }

System.ServiceModel.Activation.HttpModule是一個特殊的HttpModule,說它特別是因為當HttpModule注冊到HttpApplication的PostAuthenticateRequest事件處理程序執行後,不會再將請求進一步分發給後續的請求處理步驟。換句話說,就HttpApplication從BeginRequest到EndRequest整個請求處理的生命周期來說,對於基於.svc文件的請求僅僅延續到PostAuthenticateRequest階段。我們可以通過一種簡單的方式來證明這一點。

假設我們有一個WCF服務需要通過IIS進行寄宿,並把WCF服務相應的.svc文件定義在一個對應於某個IIS虛擬目錄的ASP.NET Website中。現在我們為之添加一個global.asax,在該global.asax,我通過如下的代碼注冊了HttpApplication處理請求的前三個事件:BeginRequest、AuthenticateRequest和PostAuthenticateRequest,當這3個事件觸發後,將一段代表當前事件的名稱寫入EventLog中。

   1: <%@ Application Language="C#" %>
2: <%@ Import Namespace= "System.Diagnostics"%>
3: <script runat="server">
4:
5: void Application_BeginRequest(object sender, EventArgs e)
6: {
7: string message = string.Format("BeginRequest Event is raised at {0}", DateTime.Now);
8: EventLog.WriteEntry("Application", message, EventLogEntryType.Information);
9: }
10:
11: void Application_AuthenticateRequest(object sender, EventArgs e)
12: {
13: string message = string.Format("AuthenticateRequst Event is raised at {0}",DateTime.Now);
14: EventLog.WriteEntry("Application", message, EventLogEntryType.Information);
15: }
16:
17: void Application_PostAuthenticateRequest(object sender, EventArgs e)
18: {
19: string message = string.Format("PostAuthenticateRequest Event is raised at {0}", DateTime.Now);
20: EventLog.WriteEntry("Application", message, EventLogEntryType.Information);
21: }
22: </script>

如果我們上面的說法成立的話,只有HttpApplication的最初3個事件被觸發。此外,HttpModule注冊的操作會先於定義在global.asax的Application_PostAuthenticateRequest方法執行,那麼在整個服務調用過程中,只有Application_BeginRequest和Application_AuthenticateRequest這兩個方法會被執行。這一點我們可以從EventLog得到證實。當我們通過執行案例7-2中的代表客戶端應用程序後,EventLog中WindowsLog的Application分組中,會多出兩個日志項目(之前已經將日志清空),如圖1所示。

圖1 通過Event Viewer查看添加的Event Log

日志的內容正是我們在Application_BeginRequest和Application_AuthenticateRequest方法中定義的日志文本。可見僅僅這兩個方法被成功執行,Application_PostAuthenticateRequest方法卻沒有被執行。可以想象,後續的事件也不可能被觸發,如圖2所示。

圖2 Event Log的詳細內容

到現在為止,我們僅僅是介紹了如何處理基於.svc文件的請求,並沒有說明.svc文件對應的WCF Service是如何被寄宿的。服務的寄宿發生在對服務.svc文件的第一次訪問,具體的實現很簡單:ServiceMode根據請求的目的地址加載相應的.svc文件,通過解析定義在<%ServiceHost%>指令的Factory和Service屬性得到ServiceHostFactory和Service的類型(Factory默認為System.ServiceMode.ServiceHostFactory),通過反射創建繼承自基類System.ServiceModel.Activation.ServiceHostFactoryBase的ServiceHostFactory對象。最後通過ServiceHostFactory創建的繼承自基類System.ServiceModel.ServiceHostBase的ServieHost對象對Serivce進行寄宿。

二、ASP.NET並行(Side by Side)模式

對於基於IIS服務寄宿,System.ServiceModel.Activation.HttpModule將基於.svc的請求劫持並分發給WCF的服務模型,從而結束了請求在ASP.NET管道的旅程。除了ASP.NET提供的一些少量的底層服務,比如動態編譯和AppDomain管理等,絕大部分ASP.NET對傳統的ASP.NET資源的請求處理機制將不會應用在基於WCF Service的請求處理流程中。從這個意義上講,我們可以說WCF Service的運行模式和ASP.NET運行時采用的是一種並行的模式。

你完全可以用一個映射到某個IIS虛擬目錄的ASP.NET Website同時作為asmx Web Service和.svc WCF Service的宿主。在這種情況下,ASP.NET .aspx Page、.asmx Web Service和WCF service運行在同一個AppDomain中。但是HttpRuntime對於.aspx Page和.asmx Web Service的處理機制並不會應用於對.svc WCF Service請求。我們把WCF Service這種寄宿模式稱為ASP.NET並行(Side by Side)模式,圖3揭示了這種寄宿模式。

圖3 ASP.NET並行模式

在圖3體現的這種情況下(ASP.NET .aspx Page和.svc WCF Service共存於同一個AppDomain),.aspx可以直接定位WCF Service,它們之間還可以共享一個基於AppDomain的狀態,比如類型的靜態屬性。但是很多ASP.NET特性將不能被WCF Service使用,比如:

HttpContext:對於WCF Service來說,HttpContext.Current永遠為null;

基於文件或者Url的授權:基於.svc文件的ACL(Access Control List)的授權和ASP.NET通過<authorization>定義的基於URL的授權都將失去效力。原因很簡單,System.ServiceModel.Activation.HttpModule在PostAuthenticateRequest階段就將請求劫持,而授權(Authorization)發生在PostAuthenticateRequest之後;

HttpModule擴展:作用於PostAuthenticateRequest事件後期的HttpModule將不會生效;

身份模擬(Impersonation):即使通過配置<identity impersonate=”true” />允許身份模擬,WCF Service總是運行在IIS進程賬號下。

不過,WCF服務模型通過自己的方式解決了上面的問題,比如:

OperationContext:ASP.NET HttpContext是基於當前的請求,WCF的OperationContext是基於當前的操作,本質上是一樣的基於上下文的容器;

ServiceAuthorizationBehavior:ServiceAuthorizationBehavior是一個Service行為,用於實現WCF的授權;

DispatchMessageInspector + 自定義Channel:DispatchMessageInspector和自定義Channel分別在服務模型和信道層對入棧消息進行額外的篩選和處理,和自定義HttpModule異曲同工;

基於操作的身份模擬(Impersonation):WCF自身也提供了基於操作的身份模擬實現。

為什麼WCF要采用這種於ASP.NET並行的模式,而不像Web Service一樣采用與ASP.NET完全兼容呢?這主要是因為WCF和.asmx Web Service有本質的區別:Web Service總是采用IIS寄宿,並使用HTTP作為傳輸,而WCF則具有不同的寄宿方式,對於傳輸協議的選擇也沒有限制。在默認的情況下,不論采用何種寄宿方式,WCF本身的行為應該保持一致。所以,讓WCF 服務的行為獨立於寄宿的環境與傳輸協議,是采用並行模式的主要原因。

三、ASP.NET兼容模式

雖然在默認的情況下,IIS的寄宿采用ASP.NET並行的模式。但是在一個Web應用中,尤其是一些AJAX的Web應用,卻明確地需要以一種ASP.NET兼容模式處理WCF Service請求。比如,在WCF Service的操作中,需要獲取ASP.NET應用的SessionState,或者是需要通過基於.svc文件的ACL對WCF Service進行授權等。

WCF對此提供了支持,實現起來也很簡單,對於編程來說,僅僅需要在Service類型加上一個特殊的AspNetCompatibilityRequirementsAttribute特性,並將RequirementsMode屬性指定為AspNetCompatibilityRequirementsMode.Allowed,實例代碼如下:

   1: [AspNetCompatibilityRequirements(
2: RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
3: public class CalculatorService:ICalculator
4: {
5: //省略成員
6: }

除此之外,WCF的配置也需要做一些修改,我們需要將<serviceHostingEnvironment/>配置節的aspNetCompatibilityEnabled屬性設為true。

   1: <?xml version="1.0"?>
2: <configuration>
3: <system.serviceModel>
4: <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
5: <!—其他配置-->
6: </system.serviceModel>
7: </configuration>

在ASP.NET兼容模式下,ASP.NET將會采用與處理.aspx、asmx一樣的方式來處理基於.svc的請求,對WCF Service請求的處理將會貫穿HttpApplication請求處理的整個生命周期(從BeginRequest到EndRequest)。對於ASP.NET兼容模式,System.ServiceModel. Activation.HttpModule將忽略對HttpApplication對象PostAuthenticateRequest事件的注冊,原本實現在HttpModule中對WCF Service的請求處理邏輯將被一個HttpHandler中:System.ServiceModel.Activation.HttpHandler。如同System.Web.UI.Page(本質上是一個HttpHandler)負責最終處理對.aspx的請求一樣,System.ServiceModel.Activation.HttpHandler服務負責最終對.svc的請求。HttpHandler是一個定義在System.ServiceModel程序集中的內部類型。HttpHandler的定義如下,請求處理實現在ProcessRequest方法中,具體的邏輯與實現在System.ServiceModel.Activation.HttpModule中的是完全一致的。

   1: internal class HttpHandler : IHttpHandler, IRequiresSessionState
2: {
3: public HttpHandler();
4: public void ProcessRequest(HttpContext context);
5:
6: public bool IsReusable { get; }
7: }
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved