在上一篇隨筆中,搭建了一個寄宿於控制台項目的wcf服務和客戶端.今天晚上時間比較充裕,看了下wcf的消息交換模式,主要分為請求應答應答模式,就是平時說的半雙工.還有一種交換模式為雙工消息交換模式.就是我們說的全雙工. 半雙工通信只需要一個契約,因為是請求應答模式,只有一個情況,那就是客戶端發送請求,服務端相應,一個契約足夠....而全雙工就不同了..客戶端可以調用服務端,反過來服務端也能調用客戶端...那么這就需要兩個服務契約,其中一個便是回調契約.CallBackContract~~~
為了方便起見,我還是在原來的代碼上進行了修改,因為是雙向通信,這其中就要存在一個會話,原來的綁定模式WSHttpBinding不支持會話的...可以選擇NetTcpBinding、NetNamedPipeBinding、WSDualHttpBinding其中的一種,我采用了NetTcpBinding.那么首先要改下服務端的綁定模式,另外,我新增加兩個地址,但是終結點還是一個..之前的基於WSHttpBinding綁定的終結點我已經注釋掉了,按理說一個服務可以有多個終結點的,但是不知道為什么,增加了這個終結點之后,開啟服務的時候報異常,請高手指點...另外剛剛說了,除了之前增加的契約之外,服務端還應該增加一個回調契約,還有一個很重要的地方,要在之前的契約上指定回調契約,如下代碼:
//定義服務的契約 [ServiceContract(CallbackContract=typeof(IProcessOrderCallBack))] public interface IProcessOrder { [OperationContract(Action="submitorder")] void SubmitOrder(Message order); [OperationContract(Action = "SomeOperationCallBack")] void SomeOperationCallBack(); }
//定義回調契約,回調契約不需要ServiceContract屬性 public interface IProcessOrderCallBack { [OperationContract(Action = "submitordercallback",IsOneWay=true)] void SomeOperationCallBack(); }
CallbackContract即為置頂的回調契約,然后在服務端定義一個類來實現回調接口:
//定義類實例接口 public class MyOrder : IProcessOrder { public void SubmitOrder(Message order) { Console.WriteLine("Message已經到達,ID為{0}:",order.Headers.MessageId.ToString()); } public void SomeOperationCallBack() { Console.WriteLine("Message已經到達,我是基於tcp/ip協議綁定的服務....既然采用了雙工通訊,回車將調用客戶端的方法:"); Console.ReadLine(); IProcessOrderCallBack callback = OperationContext.Current.GetCallbackChannel<IProcessOrderCallBack>();//從當前操作的上下文中獲取從客戶端傳過 來的實例,用它來調用客戶端的方法. callback.SomeOperationCallBack(); } }
這其中有個比較重要的地方是,
OperationContext.Current.GetCallbackChannel<IProcessOrderCallBack>(),
OperationContext這個對象很重要,它包含了當前操作的對象,在客戶端使用它可以對操作當前要傳入服務端的消息,比如更改的消息的head,在服務端可以用它獲取從服務端傳來消息的head..
GetCallbackChannel<IProcessOrderCallBack>()這個方法就是從當前從客戶端傳來的對象中獲取一個實例.然后調用客戶端的方法.
以上便是服務端的全部方法.
----------------------------------------------------------------------
客戶端:
老規矩,綁定的方式要一致,所以客戶端也要使用NetTcpBinding綁定.因為雙工通信涉及到多個契約,所以在創建通道的時候不能使用ChannelFactory,要用DuplexChannelFactory,
public class DuplexChannelFactory<TChannel> : ChannelFactory<TChannel>,可以看出,DuplexChannelFactory也是由ChannelFactory派生出來的.但是在使用的時候肯定有所不同的,
DuplexChannelFactory可以根據當前操作對象才創建通道的,什么意思呢?就是說在創建通道的時候,我們可以通過構造函數將當前操作對象的上下文傳進去,那么這個上下文對象我們也可以手工用已經實現了回調契約的對象去構造.比如MyCallBack實現了IProcessOrderCallBack..
客戶端的全部代碼
class Program { static void Main(string[] args) { Console.WriteLine("親~輸入任意字符,回車調用服務..."); Console.ReadLine(); //創建一個終結點,地址為接收程序的地址 EndpointAddress address = new EndpointAddress(@"http://localhost:4000/Order"); EndpointAddress tcpaddress = new EndpointAddress(@"net.tcp://localhost:4001/Order"); //ws綁定 WSHttpBinding bind = new WSHttpBinding(SecurityMode.None); //基於tcp/ip協議的綁定 NetTcpBinding tcpbind = new NetTcpBinding(SecurityMode.None); //創建通道 bind ChannelFactory<IProcessOrder> channel = new ChannelFactory<IProcessOrder>(bind, address); //創建基於tcp綁定模式的通道,因為雙工通信涉及到多個契約,所以在創建通道的時候不能使用ChannelFactory,要用DuplexChannelFactory, InstanceContext instanceContext = new InstanceContext(new MyCallBack()); DuplexChannelFactory<IProcessOrder> channelfactory=new DuplexChannelFactory<IProcessOrder> (instanceContext,tcpbind,tcpaddress); //使用通道工廠創建代理 IProcessOrder tcpproxy = channelfactory.CreateChannel(); tcpproxy.SomeOperationCallBack(); Console.ReadLine(); Console.ReadLine(); } } //定義服務的契約 [ServiceContract(CallbackContract = typeof(IProcessOrderCallBack))] public interface IProcessOrder { [OperationContract(Action = "submitorder")] void SubmitOrder(Message order); [OperationContract(Action = "SomeOperationCallBack")] void SomeOperationCallBack(); } //定義回調契約,回調契約不需要ServiceContract屬性 public interface IProcessOrderCallBack { [OperationContract(Action = "submitordercallback", IsOneWay = true)] void SomeOperationCallBack(); } //在客戶端定義一個類,用於實現回調契約 public class MyCallBack : IProcessOrderCallBack { public void SomeOperationCallBack() { Console.WriteLine("我是客戶端的方法,我接收到了服務端的調用..."); } }
ok,代碼已經弄完了,現在看下效果,運行~~~
在客戶端程序中按下回車:
然后在服務端輸入回車,將調用客戶單的方法,比如,在服務端的程序中輸入回車:
到此已經實現了服務端調用客戶端的方法...
寫的比較粗糙,主要想積累下自己學習的過程點點滴滴~~