WCF實現雙向通信

請求過程中的回調

這是一種比較典型的雙工消息交換模式的表現形式,客戶端在進行服務調用的時候,附加上一個回調對象;服務在對處理該處理中,通過客戶端附加的回調對象(實際上是調用回調服務的代理對象)回調客戶端的操作(該操作在客戶端執行)。整個消息交換的過程實際上由兩個基本的消息交換構成,其一是客戶端正常的服務請求,其二則是服務端對客戶端的回調。兩者可以采用請求-回復模式,也可以采用單向(One-way)的MEP進行消息交換。圖1描述瞭這樣的過程,服務調用和回調都采用請求-回復MEP。

圖1

我們沿用計算服務的例子。在這之前,我們都是調用CalculuateService直接得到計算結果,並將計算結果通過控制臺輸出。在本例中我們將采用另外一種截然不同的方式調用服務並進行結果的輸出:我們通過單向(One-way)的模式調用CalculuateService(也就是客戶端不可能通過回復消息得到計算結果),服務端在完成運算結果後,通過回調(Callback)的方式在客戶端將計算結果打印出來。

一:定義服務契約和回調契約

首先進行服務契約的定義,我們照例通過接口(ICalculator)的方式定義服務契約,作用於指定加法運算的Add操作,我們通過OperationContractAttribute特性的IsOneway屬性將操作定義成單向的操作,這意味著客戶端僅僅是向服務端發送一個運算的請求,並不會通過回復消息得到任何運算結果。

[ServiceContract(Namespace = "http://www.artech.com/", CallbackContract = typeof(ICallback))]//回調契約的類型通過ServiceContractAttribute特性的CallbackContract屬性進行指定。
public interface ICalculator
{
    [OperationContract(IsOneWay = true)]
    void Add(double x, double y);
}
//回調契約
public interface ICallback //由於定義ICalculator的時候已經通過[ServiceContract(CallbackContract=typeof(ICallback))]指明ICallback是一個服務契約瞭,所以ICallback不再需要添加ServiceContractAttribute特性。
{
    [OperationContract(IsOneWay = true)]//服務端不需要回調的返回值,索性將回調操作也設為單向方法。
    void DisplayResult(double x, double y, double result);
}

二:實現服務

在實現瞭上面定義的服務契約ICalculator的服務CalculatorService中,實現瞭Add操作,完成運算和結果顯示的工作。結果顯示是通過回調的方式實現的,所以需要借助於客戶端提供的回調對象(該對象在客戶端調用CalculatorService的時候指定,在介紹客戶端代碼的實現的時候會講到)。在WCF中,回調對象通過當前OperationContext的GetCallback<T>方法獲得(T代表回調契約的類型)。

public class CalculatorService : ICalculator
{
    public void Add(double x, double y)
    {
        double result = x + y;
        ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
        callback.DisplayResult(x, y, result);
    }
}

註: OperationContext在WCF中是一個非常重要、也是一個十分有用的對象,它代表服務操作執行的上下文。我們可以通過靜態屬性Current(OperationContext.Current)得到當前的OperationContext。借助OperationContext,我們可以在服務端或者客戶端獲取或設置一些上下文,比如在客戶端可以通過它為出棧消息(outgoing message)添加SOAP報頭,以及HTTP報頭(比如Cookie)等。在服務端,則可以通過OperationContex獲取在客戶端設置的SOAP報頭和HTTP報頭。關於OperationContext的詳細信息,可以參閱MSDN在線文檔。

三:服務寄宿

我們通過一個控制臺應用程序完成對CalculatorService的寄宿工作,並將所有的服務寄宿的參數定義在配置文件中。由於雙工通信依賴於一個雙工的信道棧,即依賴於一個能夠支持雙工通信的綁定,在此我們選用瞭NetTcpBinding。

<system.serviceModel>
       <behaviors>
       <services>
           <service name = "Artech.DuplexServices.Services.CalculatorService">
                <endpoint address = "net.tcp://127.0.0.1:9999/CalculatorService"  binding = "netTcpBinding" contract = "Artech.DuplexServices.Contracts.ICalculator"/>
             </service>
         </services>
 </system.serviceModel>

註: 在WCF預定義綁定類型中,WSDualHttpBinding和NetTcpBinding均提供瞭對雙工通信的支持,但是兩者在對雙工通信的實現機制上卻有本質的區別。WSDualHttpBinding是基於HTTP傳輸協議的;而HTTP協議本身是基於請求-回復的傳輸協議,基於HTTP的通道本質上都是單向的。WSDualHttpBinding實際上創建瞭兩個通道,一個用於客戶端向服務端的通信,而另一個則用於服務端到客戶端的通信,從而間接地提供瞭雙工通信的實現。而NetTcpBinding完全基於支持雙工通信的TCP協議。

using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
{
    host.Open();
    Console.Read();
}

四:實現回調契約與服務調用

在客戶端程序為回調契約提供實現,在下面的代碼中CalculateCallback實現瞭回調契約ICallback,在DisplayResult方法中對運算結果進行輸出。

class CalculateCallback : ICallback
{
    public void DisplayResult(double x, double y, double result)
    {
        Console.WriteLine("x + y = {2} when x = {0} and y = {1}", x, y, result);
    }
}

接下來實現對雙工服務的調用,下面是相關的配置和托管程序。在服務調用程序中,通過DuplexChannelFactory<TChannel>創建服務代理對象,DuplexChannelFactory<TChannel>和ChannelFactory<TChannel>的功能都是一個服務代理對象的創建工廠,不過DuplexChannelFactory<TChannel>專門用於基於雙工通信的服務代理的創建。在創建DuplexChannelFactory<TChannel>之前,先創建回調對象,並通過InstanceContext對回調對象進行包裝。

<system.serviceModel>
     <client>
         <endpoint name = "CalculatorService" address = "net.tcp://127.0.0.1:9999/CalculatorService" binding = "netTcpBinding" contract = "Artech.DuplexServices.Contracts.ICalculator"/>
     </client>
 </system.serviceModel>
InstanceContext instanceContext = new InstanceContext(new CalculateCallback());
using (DuplexChannelFactory<ICalculator> channelFactory = new DuplexChannelFactory<ICalculator>(instanceContext, "CalculatorService"))
{
    ICalculator proxy = channelFactory.CreateChannel();
    using (proxy as IDisposable)
    {
        proxy.Add(1, 2);
        Console.Read();
    }
}

註意:如果采用WsDualHttpBinding,由於回調的服務監聽地址采用的默認端口是80,在IIS 5.x以及之前的版本中,80端口是IIS獨占的監聽端口。WsDualHttpBinding定義瞭一個ClientBaseAddress使你能很容易地改變回調服務的基地址。對於我們給出的案例,我們隻要通過下面的配置將clientBaseAddress設為可用的地址(http://127.0.0.1:8888/ CalculatorService) 
< bindings >
     < wsDualHttpBinding >
         < binding name = "MyBinding" clientBaseAddress = "http://127.0.0.1:8888/calculatecallback" />
        </ wsDualHttpBinding >
  </ bindings >

到此這篇關於WCF實現雙向通信的文章就介紹到這瞭。希望對大傢的學習有所幫助,也希望大傢多多支持LevelAH。

推薦閱讀: