3.1.3 案例演示:如何直接通过绑定进行消息通信
现在通过一个简单的例子,演示如何直接通过绑定(在这里使用最简单的BasicHttpBinding)进行消息通信。整个解决方案由两个Console应用组成,它们分别模拟消息的监听方与发送方,案例应用的结构如图3-3所示。
图3-3 基于绑定通信案例的应用结构
步骤一 创建请求监听端应用程序
namespace Artech.MessagingViaBinding.Listener { class Program { static void Main(string[] args) { Uri listenUri = new Uri("http://127.0.0.1:9999/listener"); Binding binding = new BasicHttpBinding(); IChannelListener<IReplyChannel> channelListener = binding. BuildChannelListener<IReplyChannel>(listenUri); channelListener.Open();
IReplyChannel channel = channelListener.AcceptChannel (TimeSpan.MaxValue); channel.Open(); Console.WriteLine("开始监听..."); while (true) { (TimeSpan.MaxValue); requestContext.RequestMessage); requestContext.Reply(CreateReplyMessage(binding)); } } static Message CreateReplyMessage(Binding binding) { string action = "urn:artech.com/reply"; string body = "这是一个简单的回复消息!"; return Message.CreateMessage(binding.MessageVersion,action,body); } } }
我们通过代码分解,对代码执行的流程进行简单的介绍:首先,BasicHttpBinding对象被创建出来,调用绑定对象的BuildChannelListener<IReplyChannel>方法,创建IChannelListener<IReplyChannel>对象。该方法接收一个URI类型的参数,表示监听地址。调用Open方法开启创建出来的信道监听器(IChannelListener<IReplyChannel>)对象。
Uri listenUri = new Uri("http://127.0.0.1:9999/listener"); Binding binding = new BasicHttpBinding(); IChannelListener<IReplyChannel> channelListener = binding.BuildChannelListener<IReplyChannel>(listenUri); channelListener.Open();
在信道监听器通过绑定对象被成功创建并开启后,通过调用AcceptChannel方法创建信道栈进行请求的监听,信道栈通过若干信道有序连接而成,方法最终返回的是位于栈顶的信道对象。
IReplyChannel channel = channelListener.AcceptChannel(TimeSpan.MaxValue); channel.Open();
一旦信道栈被成功创建,那么就可以利用它对请求消息进行接收、处理了。在本例中,通过一个无限循环来处理来自不同客户端的消息请求。请求的接收通过IReplyChannel的ReceiveRequest方法实现。该方法接受一个TimeSpan类型参数,代表该方法从执行开始成功接受请求的时间,由于客户端请求的频率不确定,在这里给它指定了一个最大值。ReceiveRequest并不像我们想象的一样返回一个代表请求消息的Message对象,而是返回一个RequestContext对象,并通过该对象将创建的回复消息回复给请求方。
注: 在请求/回复消息交换模式中,RequestContext是连接请求和回复的纽带。RequestContext不仅仅是对请求消息的封装,还可以用于回复消息的发送。在本例中,我们通过它的RequestMessage属性得到请求消息,然后通过CreateReplyMessage方法创建一个回复消息,通过Reply方法回复给发送方。
RequestContext requestContext = channel.ReceiveRequest(TimeSpan.MaxValue); Console.WriteLine("接收到请求消息:\n{0}", requestContext.RequestMessage); requestContext.Reply(CreateReplyMessage(binding));
在创建回复消息的时候,须要考虑消息的版本问题。在WCF中,消息版本通过System.ServiceModel.Channels.MessageVersion类表示,一般消息的版本包含两个部分的内容:SOAP的版本和WS-Addressing的版本,它们分别通过System.ServiceModel.Channels. AddressingVersion和System.ServiceModel.Channels.AddressingVersion表示。对一个绑定对象来说,并不是所有的MessageVersion都支持,为此,在创建回复消息的时候,通过具体的绑定对象确定回复消息的MessageVersion。
static Message CreateReplyMessage(Binding binding) { string action = "urn:artech.com/reply"; string body = "这是一个简单的回复消息!"; return Message.CreateMessage(binding.MessageVersion, action, body); }
步骤二 创建消息发送端应用程序
namespace Artech.MessagingViaBinding.Sender { class Program { static void Main(string[] args) { Uri listenUri = new Uri("http://127.0.0.1:9999/listener"); Binding binding = new BasicHttpBinding(); IChannelFactory<IRequestChannel> channelFactory = binding.BuildChannelFactory<IRequestChannel>(); channelFactory.Open(); IRequestChannel channel = channelFactory.CreateChannel(new EndpointAddress(listenUri)); channel.Open(); Message replyMessage = channel.Request(CreateRequestMessage (binding)); Console.WriteLine("接收到回复消息\n{0}", replyMessage); Console.Read(); } static Message CreateRequestMessage(Binding binding) { string action = "urn:artech.com/request"; string body = "这是一个简单的请求消息!"; return Message.CreateMessage(binding.MessageVersion,action,body); } } }
发送端的程序和监听端类似,在监听程序中,通过绑定创建了IChannelListener<IReplyChannel>对象,并调用AcceptChannel方法创建监听信道栈并进行消息的接收与处理。与之相对,在客户端我们通过绑定创建IChannelFactory<IRequestChannel>对象,并通过该对象创建信道栈进行请求消息的发送。
Binding binding = new BasicHttpBinding(); IChannelFactory<IRequestChannel> channelFactory = binding.BuildChannelFactory<IRequestChannel>(); channelFactory.Open();
输出结果
成功创建了请求监听端和消息发送端的应用程序之后,先后运行这两个控制台的应用程序,对于监听端,将会出现如图3-4的输出结果。<s:Envelope>包含的内容正是在消息发送端生成并发送的SOAP消息的内容。
图3-4 基于绑定通信案例监听端运行结果
由于监听端在接收到请求消息后,向请求端返回了一个回复消息,这个回复消息将会成功输出到消息请求端。图3-5是消息发送端运行时的真实输出结果。
图3-5 基于绑定通信案例请求端运行结果