雙工(Duplex)模式的消息交換方式體現在消息交換過程中,參與的雙方均可以向對方發送消息。基於雙工MEP消息交換可以看成是多個基本模式下(比如請求-回復模式和單項模式)消息交換的組合。雙工MEP又具有一些變體,比如典型的訂閱-發布模式就可以看成是雙工模式的一種表現形式。雙工消息交換模式使服務端回調(Callback)客戶端操作成為可能。本文測試Mono 3.0.2/.NET 4對雙工(Duplex)模式的WCF支持。
演示基於雙工通信的WCF應用是一個簡單的計算服務CalculatorService,我們通過單向(One-way)的模式調用CalculuateService(也就是客戶端不可能通過回復消息得到計算結果),服務端在完成運算結果后,通過回調(Callback)的方式在客戶端將計算結果打印出來。
步驟一:定義服務契約和回調契約
首先進行服務契約的定義,我們照例通過接口(ICalculator)的方式定義服務契約,作用於指定加法運算的Add操作,我們通過OperationContractAttribute特性的IsOneway屬性將操作定義成單向的操作,這意味着客戶端僅僅是向服務端發送一個運算的請求,並不會通過回復消息得到任何運算結果。
通過在服務端回調客戶端操作的方式實現運算結果的輸出。客戶端調用CalculatorService正常的服務調用,那么在服務執行過程中借助於客戶端在服務調用時提供的回調對象對客戶端的操作進行回調,從本質上講是另外一種形式的服務調用。WCF采用基於服務契約的調用形式,客戶端正常的服務調用需要服務契約,同理服務端回調客戶端依然需要通過描述回調操作的服務契約,我們把這種服務契約稱為回調契約。回調契約的類型通過ServiceContractAttribute特性的CallbackContract屬性進行指定。
上面代碼中服務契約ICalculator的回調契約ICallback定義如下。由於回調契約本質也是一個服務契約,所以定義方式和一般意義上的服務契約基本一樣。ICallback定義了一個服務操作DisplayResult用於顯示運算結果(前兩個參數為執行加法運算的操作數),由於服務端不需要回調的返回值,索性將回調操作也設為單向方法。
步驟二:實現服務
在實現了上面定義的服務契約ICalculator的服務CalculatorService中,實現了Add操作,完成運算和結果顯示的工作。結果顯示是通過回調的方式實現的,所以需要借助於客戶端提供的回調對象(該對象在客戶端調用CalculatorService的時候指定,在介紹客戶端代碼的實現的時候會講到)。在WCF中,回調對象通過當前OperationContext的GetCallback<T>方法獲得(T代表回調契約的類型)。
OperationContext在WCF中是一個非常重要、也是一個十分有用的對象,它代表服務操作執行的上下文。我們可以通過靜態屬性Current(OperationContext.Current)得到當前的OperationContext。借助OperationContext,我們可以在服務端或者客戶端獲取或設置一些上下文,比如在客戶端可以通過它為出棧消息(outgoing message)添加SOAP報頭,以及HTTP報頭(比如Cookie)等。在服務端,則可以通過OperationContex獲取在客戶端設置的SOAP報頭和HTTP報頭。
步驟三:服務寄宿
我們通過一個控制台應用程序完成對CalculatorService的寄宿工作,並將所有的服務寄宿的參數定義在配置文件中。由於雙工通信依賴於一個雙工的信道棧,即依賴於一個能夠支持雙工通信的綁定,在此我們選用了NetTcpBinding,Mono下的wsDualHttpBinding 是不支持的哦,具體可以參看 http://www.mono-project.com/WCF_Development。
<?xml version="1.0"?>
<configuration> <system.serviceModel> <services> <service name="DuplexWCF.Service.CalculatorService" behaviorConfiguration="duplexWcf"> <endpoint address="net.tcp://192.168.10.96:9999/calculator" binding="netTcpBinding" bindingConfiguration="duplexnetTcpBinding" contract="DuplexWCF.Contract.ICalculator"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="duplexWcf"> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> </behaviors>
<bindings>
<netTcpBinding>
<binding name = "duplexnetTcpBinding">
<security mode ="None" />
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration> 注: 在WCF預定義綁定類型中,WSDualHttpBinding和NetTcpBinding均提供了對雙工通信的支持,但是兩者在對雙工通信的實現機制上卻有本質的區別。WSDualHttpBinding是基於HTTP傳輸協議的;而HTTP協議本身是基於請求-回復的傳輸協議,基於HTTP的通道本質上都是單向的。WSDualHttpBinding實際上創建了兩個通道,一個用於客戶端向服務端的通信,而另一個則用於服務端到客戶端的通信,從而間接地提供了雙工通信的實現。而NetTcpBinding完全基於支持雙工通信的TCP協議。
配置里頭<endpoint address="net.tcp://192.168.10.96:9999/calculator" 使用localhost代替具體的ip時候出現無法連接的情況。
MONO_STRICT_MS_COMPLIANT 這個環境變量也不需要了哈,完全原生的Linux支持了哦,之前有網友碰到過WCF的兼容性問題是通過設置環境變量來兼容.NET的。具體可以參看
步驟四:實現回調契約
在客戶端程序為回調契約提供實現,在下面的代碼中CalculateCallback實現了回調契約ICallback,在DisplayResult方法中對運算結果進行輸出。
步驟五:服務調用
接下來實現對雙工服務的調用,下面是相關的配置和托管程序。在服務調用程序中,通過DuplexChannelFactory<TChannel>創建服務代理對象,DuplexChannelFactory<TChannel>和ChannelFactory<TChannel>的功能都是一個服務代理對象的創建工廠,不過DuplexChannelFactory<TChannel>專門用於基於雙工通信的服務代理的創建。在創建DuplexChannelFactory<TChannel>之前,先創建回調對象,並通過InstanceContext對回調對象進行包裝。
在服務寄宿程序啟用的情況下,運行客戶端程序后,通過服務端執行的運算結果會通過回調客戶端的操作顯示出來,下面是最終輸出的結果。
代碼下載
相關文章: