您的位置:首页 > 编程语言

WCF后传系列(9):深度通道编程模型Part 2—实例篇

2008-11-14 00:22 609 查看

引言

从本质上说,WCF是一个通信服务框架,它允许我们使用不同的传输协议,使用不同的消息编码形式,跟不同的WS-*系列规范交互,而所有这些细节都是由通道堆栈来处理的。在《WCF专题系列(8):深度通道编程模型Part 1—设计篇》中,对于WCF中的通道模型有了深入的认识,本文中,我将通过实例来说明在通道模型中,服务端是如何接收消息,客户端是如何发送消息的。

服务端通道

本文将不使用WCF的编程模型,而直接利用通道模型来进行通信,这样有助于我们更进一步加深对服务端处理消息的认识,在服务端侦听并接收消息的第一步需要创建绑定,我们既可以使用WCF中内置的绑定或者使用自定义的绑定,如下代码所示,创建一个CustomBinding:
// 创建自定义绑定
BindingElement[] bindingElements = new BindingElement[2];
bindingElements[0] = new TextMessageEncodingBindingElement();
bindingElements[1] = new HttpTransportBindingElement();
CustomBinding binding = new CustomBinding(bindingElements);

此处添加了HttpTransportBindingElement,所以生成的通道堆栈具有HTTP传输通道,另外采用了文本消息编码器。接下来调用刚才创建的CustomBinding的BuildChannelListener方法来构造通道侦听器,需要指定侦听基地址以及绑定参数,另外调用Open()方法打开通道监听器,相信大家一定还记得Open()方法是在接口ICommunicationObject中定义的,如下代码所示:
// 使用自定义绑定创建通道侦听器
IChannelListener<IReplyChannel> listener =
binding.BuildChannelListener<IReplyChannel>(
new Uri("http://localhost:8887/StringService"),
new BindingParameterCollection());
// 监听消息
listener.Open();
Console.WriteLine("Listening for incoming channel connections");

现在侦听传入的消息,由于我们使用请求了响应消息交换模式,此处侦听器返回一个实现了IReplyChannel的通道,为了在此通道上接收消息,我们首先对其调用Open()方法(该方法仍然是在ICommunicationObject中定义),以便将其置于一个准备进行通信的状态。 然后,我们调用ReceiveRequest()方法,它会处于阻止状态,直到消息达到,如下代码所示:
// 创建Reply通道
IReplyChannel channel = listener.AcceptChannel();
Console.WriteLine("Channel accepted. Listening for messages");
channel.Open();
RequestContext request = channel.ReceiveRequest();

当ReceiveRequest()方法返回一个RequestContext时,再使用其RequestMessage属性获取接收到的消息。输出消息的操作(Action)和内容。为了发送答复,在此例中创建一个新的答复消息,它会将我们在请求中接收到的字符串数据,添加一段字符后再传递回去。然后,调用Reply()方法以发送答复消息,如下代码所示:
// 读取请求的消息
Message message = request.RequestMessage;
Console.WriteLine("Message Received");
Console.WriteLine("Message Action: {0}", message.Headers.Action);
string body = message.GetBody<string>();
Console.WriteLine("Message Content: {0}", body);
// 发送响应消息
Message replymessage = Message.CreateMessage(
binding.MessageVersion,
"http://www.cnblogs.com/TerryLee/Encode",
"Hello : " + body);
request.Reply(replymessage);

最后别忘了做资源释放工作,关闭通道侦听器、通道、请求消息、请求上下文等,如下代码所示:
// 释放对象
message.Close();
request.Close();
channel.Close();
listener.Close();

完整的代码如下所示:
/// <summary>
/// Author:TerryLee
/// Url:http://www.cnblogs.com/terrylee
/// </summary>
static void Main()
{
// 创建自定义绑定 BindingElement[] bindingElements = new BindingElement[2]; bindingElements[0] = new TextMessageEncodingBindingElement(); bindingElements[1] = new HttpTransportBindingElement(); CustomBinding binding = new CustomBinding(bindingElements);
// 使用自定义绑定创建通道侦听器 IChannelListener<IReplyChannel> listener = binding.BuildChannelListener<IReplyChannel>( new Uri("http://localhost:8887/StringService"), new BindingParameterCollection()); // 监听消息 listener.Open(); Console.WriteLine("Listening for incoming channel connections");
// 创建Reply通道 IReplyChannel channel = listener.AcceptChannel(); Console.WriteLine("Channel accepted. Listening for messages"); channel.Open(); RequestContext request = channel.ReceiveRequest();
// 读取请求的消息 Message message = request.RequestMessage; Console.WriteLine("Message Received"); Console.WriteLine("Message Action: {0}", message.Headers.Action); string body = message.GetBody<string>(); Console.WriteLine("Message Content: {0}", body); // 发送响应消息 Message replymessage = Message.CreateMessage( binding.MessageVersion, "http://www.cnblogs.com/TerryLee/Encode", "Hello : " + body); request.Reply(replymessage);
// 释放对象 message.Close(); request.Close(); channel.Close(); listener.Close();
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}

现在运行服务端如图1所示,由于没有消息到达,所以ReceiveRequest()方法会阻塞:



图 1

客户端通道

前面完成了服务端的工作,接下来我们看看如何在客户端直接使用通道模型进行通信。与服务端一致,请求消息的第一步是创建绑定,因为双方需要通过绑定就通信的细节达成一致。创建自定义绑定与服务端一致,如下代码所示:
// 创建绑定
BindingElement[] bindingElements = new BindingElement[2];
bindingElements[0] = new TextMessageEncodingBindingElement();
bindingElements[1] = new HttpTransportBindingElement();
CustomBinding binding = new CustomBinding(bindingElements);

接下来需要使用刚才创建的绑定来构造通道工厂,在上一篇中我们提到,消息的接收方使用通道侦听器,而消息的请求方使用通道工厂,这次使用BuildChannelFactory()方法构造通道工厂并打开,如下代码所示:
// 使用绑定创建通道工厂
IChannelFactory<IRequestChannel> factory =
binding.BuildChannelFactory<IRequestChannel>(
new BindingParameterCollection());
// 打开通道工厂
factory.Open();
Console.WriteLine("Channel factory opened");

现在使用通道工厂的CreateChannel()方法来创建IRequestChannel,得到通道后,调用它的Open()方法以使其处于通信就绪状态,如下代码所示:
// 创建Request通道
IRequestChannel channel = factory.CreateChannel(
new EndpointAddress("http://localhost:8887/StringService"));
channel.Open();
Console.WriteLine("Request channel opened");

打开通道之后,就可以创建消息并使用通道的 Request()方法发送请求并等待响应,这里我们发送的消息内容是“TerryLee”,当此方法返回时,我们将能够得到回复消息,可以读取该消息以发现终结点回复的内容,如下代码所示:
// 创建请求消息
Message requestmessage = Message.CreateMessage(
binding.MessageVersion,
"http://www.cnblogs.com/TerryLee/Encode",
"TerryLee");
// 发送请求消息并接收响应消息
Message replymessage = channel.Request(requestmessage);
Console.WriteLine("Reply message received");
Console.WriteLine("Reply action: {0}",
replymessage.Headers.Action);
string data = replymessage.GetBody<string>();
Console.WriteLine("Reply content: {0}", data);

最后仍然是资源释放工作,关闭通道工厂、通道以及请求消息,如下代码所示:
replymessage.Close();
channel.Close();
factory.Close();

完整的客户端代码为:
/// <summary>
/// Author:TerryLee
/// Url:http://www.cnblogs.com/terrylee
/// </summary>
public static void Main()
{
// 创建绑定 BindingElement[] bindingElements = new BindingElement[2]; bindingElements[0] = new TextMessageEncodingBindingElement(); bindingElements[1] = new HttpTransportBindingElement(); CustomBinding binding = new CustomBinding(bindingElements);
// 使用绑定创建通道工厂 IChannelFactory<IRequestChannel> factory = binding.BuildChannelFactory<IRequestChannel>( new BindingParameterCollection()); // 打开通道工厂 factory.Open(); Console.WriteLine("Channel factory opened");
// 创建Request通道 IRequestChannel channel = factory.CreateChannel( new EndpointAddress("http://localhost:8887/StringService")); channel.Open(); Console.WriteLine("Request channel opened");
// 创建请求消息 Message requestmessage = Message.CreateMessage( binding.MessageVersion, "http://www.cnblogs.com/TerryLee/Encode", "TerryLee"); // 发送请求消息并接收响应消息 Message replymessage = channel.Request(requestmessage); Console.WriteLine("Reply message received"); Console.WriteLine("Reply action: {0}", replymessage.Headers.Action); string data = replymessage.GetBody<string>(); Console.WriteLine("Reply content: {0}", data);
replymessage.Close(); channel.Close(); factory.Close();
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}

最后运行时服务端如图2所示:



图 2
客户端如图3所示:



图 3

温故知新

现在我们再回顾一下上一篇中所讲的知识,通道对象模型是实现通道、通道侦听器和通道工厂所必需的一组核心接口。还提供一些基类以辅助自定义实现。可以看到通道模型中最重要的有三组接口:通道、通道侦听器和通道工厂。每个通道均实现一个或多个接口,称为通道形状接口或通道形状;通道侦听器负责侦听传入消息,即在消息的接收端,然后通过由通道侦听器创建的通道将这些消息传送到上面的层;通道工厂负责创建通道用于发送消息,即在消息的发送方,并在通道工厂关闭时,关闭通道工厂创建的所有通道。如图4所示:



图 4
对照本文的示例代码,相信大家对于图4能够有更深的认识。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息