在上一篇随笔中,搭建了一个寄宿于控制台项目的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,代码已经弄完了,现在看下效果,运行~~~
在客户端程序中按下回车:
然后在服务端输入回车,将调用客户单的方法,比如,在服务端的程序中输入回车:
到此已经实现了服务端调用客户端的方法...
写的比较粗糙,主要想积累下自己学习的过程点点滴滴~~