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

引言

从本质上说,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:[url]http://www.cnblogs.com/terrylee[/url]
/// </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()方法会阻塞:
TerryLee_WCF_31
图 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:[url]http://www.cnblogs.com/terrylee[/url]
/// </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所示:
TerryLee_WCF_33 
图 2
客户端如图3所示:
TerryLee_WCF_32
图 3

温故知新

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

0javascript

收藏css

lihuijun

203篇文章,74W+人气,0粉丝

Ctrl+Enter 发布html

发布java

取消jquery

扫一扫,领取大礼包git

0ajax

分享
lihuijun
相关文章
相关标签/搜索