前言:
在WCF初探-5:WCF消息交换模式之双工通讯(Duplex)博文中,我讲解了双工通信服务的一个应用场景,即订阅和发布模式,这一篇,我将通过一个消息发送的例子讲解一下WCF客户端如何为双工服务创建回调对象。
双工服务指定一个回调协定,客户端应用程序必须实现该协定以便提供一个该服务能够根据协定要求调用的回调对象。虽然回调对象不是完整的服务(例如,您无法使用回调对象启动一个通道),但是为了实现和配置,这些回调对象可以被视为一种服务。
双工服务的客户端必须:
- 实现一个回调协定类。
- 创建回调协定实现类的一个实例,并使用该实例创建传递给 WCF 客户端构造函数的 System.ServiceModel.InstanceContext 对象。
- 调用操作并处理操作回调。
双工 WCF 客户端对象除了会公开支持回调所必需的功能(包括回调服务的配置)以外,其他的功能和它们的非双工对应项相同。
示例说明:
- Service服务契约中定义了一个发送方法Send,采用IsOneWay=true,供客户端调用,向服务端发送消息。Service中还提供了用于双工通信的回调接口IMessageExchangeCallback,该接口中定义了服务端接收消息后向客户端发送消息的方法Receive,此方法就是客户端发送消息到服务端后,服务端调用回调方法,将消息发送到客户端。
- Client需要实现双工协定回调接口的类CallBackHandler,并实现Receive方法。
- 针对双工协定生成的 WCF 客户端需要在构造时提供一个 InstanceContext 类。此 InstanceContext 类用作实现回调接口并处理从服务发送回的消息的对象所在的位置。InstanceContext 类是用 CallbackHandler 类的实例构造的。此对象处理通过回调接口从服务发送到客户端的消息。
WCF客户端为双工服务创建回调对象示例:
- 解决方案如下:
- 工程结构说明:
- Service:类库程序,定义服务契约接口和回调接口,实现服务契约。在IMessageExchange中定义了Send方法,并且还定义了双工服务回调接口 IMessageExchangeCallback。
IMessageExchange.cs的代码如下:
using System.ServiceModel; using System.Collections.Generic; using System.Runtime.Serialization; namespace Service { [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IMessageExchangeCallback))] public interface IMessageExchange { [OperationContract(IsOneWay=true)] void Send(string message); } public interface IMessageExchangeCallback { [OperationContract(IsOneWay = true)] void Receive(string message); } }
MessageExchange.cs的代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace Service { [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)] public class MessageExchange : IMessageExchange { public void Send(string message) { Console.WriteLine("服务端监听客户端发出的消息:" + message); Callback.Receive(message); } IMessageExchangeCallback Callback { get { return OperationContext.Current.GetCallbackChannel<IMessageExchangeCallback>(); } } } }
注意:回调契约接口IMessageExchangeCallback中的Receive方法是在客户端实现的,所以如果需要在服务端调用回调方法就必须通过当前操作的实例上下文来获取,即上面代码中的Callback对象。
2. Host:控制台应用程序。提供服务寄宿程序,添加对Srevice程序集的引用。完成配置文件和代码就可以承载服务。
Program.cs的代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Service; using System.ServiceModel; namespace Host { class Program { static void Main(string[] args) { using (ServiceHost host = new ServiceHost(typeof(MessageExchange))) { host.Opened += delegate { Console.WriteLine("服务已经启动,按任意键终止!"); }; host.Open(); Console.Read(); } } } }
App.config的代码如下:
<?xml version="1.0"?> <configuration> <system.serviceModel> <services> <service name="Service.MessageExchange" behaviorConfiguration="mexBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:1234/MessageExchange/"/> </baseAddresses> </host> <endpoint address="" binding="wsDualHttpBinding" contract="Service.IMessageExchange" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="mexBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
3. Client:控制台应用程序。客户端程序,启动服务承载程序Host后,添加对服务地址http://localhost:1234/MessageExchange/的引用,将命名空间修改为
MessageExchangeServiceRef,之后在Program.cs完成对双工服务回调接口IMessageExchangeCallback的实现和对服务方法的调用。Program.cs的代码如下:
using System; using Client.MessageExchangeServiceRef; using System.ServiceModel; namespace Client1 { public class CallBackHandler : IMessageExchangeCallback { public void Receive(string message) { Console.WriteLine("客户端监听服务端接收的消息:" + message); } } class Program { static void Main(string[] args) { InstanceContext instanceContext = new InstanceContext(new CallBackHandler()); MessageExchangeClient proxy = new MessageExchangeClient(instanceContext); proxy.Send("Wcf Duplex"); Console.Read(); } } }
运行结果如下:
总结:
- 本文模拟了客户端向服务端发送消息,服务端接收到消息后,将监听到的消息显示在客户端。希望通过本示例对双工通信有进步一的认识,关于实例和会话,我将在后面的博文中做解析。