在《基於IIS的WCF服務寄宿(Hosting)實現揭秘》中,我們談到在採用基於IIS(或者說基於ASP.NET)的WCF服務寄宿中,具有兩種截然不同的運行模式:ASP.NET並行(Side by Side)模式和ASP.NET相容模式。對於前者,WCF通過HttpModule實現了服務的寄宿,而對於後者,WCF的服務寄宿通過一個HttpHandler實現。只有在ASP.NET相容模式下,我們熟悉的一些ASP.NET機制才能被我們使用,比如通過HttpContext的請求下下文;基於檔案或者Url的授權;HttpModule擴充;身份類比(Impersonation)等。
由於在ASP.NET相容模式下,ASP.NET採用與.aspx Page完全一樣的方式處理基於.svc的請求,換言之,我們就可以藉助當前HttpContext的SessionState維護工作階段狀態,進而建立一個支援會話的WCF Service。接下來,我們就通過一個簡單的例子,一步步地建立這樣的會話服務。本案例採用如圖1所示的3層結構。
圖1 ASP.NET相容模式案例應用結構
步驟一、定義服務契約:ICalculator
案例依然沿用計算服務的例子,不過通過原來直接與傳入運算元並得到運算結果的方式不同,為了體現工作階段狀態的存在,我們將本案例的WCF服務定義成“累積計算服務”:保留上一次運算的結果,並將其作為後續運算的運算元。為此,定義了如下一個介面作為服務契約:前面4個操作代表基本的加、減、乘、除運算,計算結果通過GetResult方法獲得。
1: using System.ServiceModel;
2: namespace Artech.AspCompatibleServices.Contracts
3: {
4: [ServiceContract]
5: public interface ICalculator
6: {
7: [OperationContract]
8: void Add(double x);
9: [OperationContract]
10: void Subtract(double x);
11: [OperationContract]
12: void Multiply(double x);
13: [OperationContract]
14: void Divide(double x);
15: [OperationContract]
16: double GetResult();
17: }
18: }
步驟二、實現服務:CalculatorService
服務的實現和.svc都定義在一個ASP.NET Web網站項目中。對於定義在 CalculatorService中的每次運算,先通過HttpContext從SessionState中取出上一次運算的結果,完成運算後再將新的運算結果儲存到SessionState中。通過在CalculatorService上應用AspNetCompatibilityRequirementsAttribute實現對ASP.NET相容模式的支援。
1: using System.ServiceModel.Activation;
2: using System.Web;
3: using Artech.AspCompatibleServices.Contracts;
4: [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
5: public class CalculatorService : ICalculator
6: {
7: public void Add(double x)
8: {
9: HttpContext.Current.Session["__Result"] = GetResult() + x;
10: }
11: public void Subtract(double x)
12: {
13: HttpContext.Current.Session["__Result"] = GetResult() - x;
14: }
15: public void Multiply(double x)
16: {
17: HttpContext.Current.Session["__Result"] = GetResult() * x;
18: }
19: public void Divide(double x)
20: {
21: HttpContext.Current.Session["__Result"] = GetResult() / x;
22: }
23: public double GetResult()
24: {
25: if (HttpContext.Current.Session["__Result"] == null)
26: {
27: HttpContext.Current.Session["__Result"] = 0.0;
28: }
29: return (double)HttpContext.Current.Session["__Result"];
30: }
31: }
下面是CalculatorService對應的.svc的定義和Web.config。為了簡潔,在<@ServiceHost%>指令中,僅僅設定一個必需屬性Service。對於ASP.NET相容模式的支援,配置<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>必不可少。
1: <?xml version="1.0"?>
2: <configuration>
3: <system.serviceModel>
4: <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
5: <services>
6: <service name="CalculatorService">
7: <endpoint binding="wsHttpBinding" contract="Artech.AspCompatibleServices.Contracts.ICalculator" />
8: </service>
9: </services>
10: </system.serviceModel>
11: </configuration>