引言
从本质上说,WCF是一个通信服务框架,它允许我们使用不同的传输协议,使用不同的消息编码形式,跟不同的WS-*系列规范交互,而所有这些细节都是由通道堆栈来处理的。为了简化这些处理,在WCF中提供了两种模型,一是针对开发者的应用程序编程模型;二是用来通信的通道模型,这样对于开发者来说,只要了解应用程序编程模型就足够了,而不会涉及到通道模型,然而,对于通道模型进行必要的学习,可以让我们真正理解WCF中“通信”概念,了解WCF的 整个架构体系,从而构建出更加健壮的WCF服务或者对WCF框架进行扩展。在本文中,我们将进行深度了解WCF中的通道模型是如何设计的。
通道模型概述
在WCF中,提供了一系列的接口和其它类型模型,它们为消息的发送和接收提供了一个底层的编程模型,该模型称之为WCF通道模型。在通道模型中,一个很重要的概念是通道堆栈,它是具有一个或多个消息处理通道的分层的通信堆栈,堆栈中放置了各种类型的通道,用来对象进行处理,如在通道堆栈的最底层放置了传输通道,它负责使通道堆栈适应基础传输,如图1所示:
图1
在通道堆栈中,不仅仅提供消息的传输方式,还提供了其它诸如对消息的内容或者消息头进行处理的功能,这些功能同样是以通道的方式放置在通道堆栈中,甚至于我们可以编写自己的通道,加入到通道堆栈中。
消息在通道堆栈中传输时,将作为Message对象流过通信堆栈,如传输通道负责在发送方和接收方之间转换消息,之后消息将通过传输通道继续往上流,依次经过通道堆栈中的各个通道,这些通道各自负责提供一种通信功能,如在消息头中添加信息,对消息的正文进行加密等等。
通道对象模型
通道对象模型是实现通道、通道侦听器和通道工厂所必需的一组核心接口。还提供一些基类以辅助自定义实现。可以看到通道模型中最重要的有三组接口:通道、通道侦听器和通道工厂。每个通道均实现一个或多个接口,称为通道形状接口或通道形状;通道侦听器负责侦听传入消息,即在消息的接收端,然后通过由通道侦听器创建的通道将这些消息传送到上面的层;通道工厂负责创建通道用于发送消息,即在消息的发送方,并在通道工厂关闭时,关闭通道工厂创建的所有通道。
在通道模型中,最重要的一个接口是ICommunicationObject,它定义了所有通信对象实现的基本状态机的核心接口,自定义通道通信对象可以直接实现ICommunicationObject,如图2所示:
图2
只有图2中的这些接口,才属于WCF的通道模型,在WCF中同样提供了一些基类如CommunicationObject、ChannelFactoryBase等,在实现自定义的通道通信对象时,也可以直接继承于这些基类,但要注意,这些基类仅仅是为实现自定义通道通信对象提供了方便,它们本身并不属于通道模型的一部分。
ICommunicationObject接口为WCF中所有面向通信的对象提供了契约,除了通道、通道侦听器、通道工厂外,还有调度程序和服务主机,定义了基本状态的协定。它包括一组用于启动状态转换的打开、关闭和中止方法,打开和关闭方法的异步版本,一组提供状态转换通知的事件和一个个用于检查对象状态的公开State属性,它的定义如下所示:
public interface ICommunicationObject { // 状态属性 CommunicationState State { get; } // 事件 event EventHandler Closed; event EventHandler Closing; event EventHandler Faulted; event EventHandler Opened; event EventHandler Opening; // 方法 void Abort(); void Close(); void Close(TimeSpan timeout); void Open(); void Open(TimeSpan timeout); // 异步方法 IAsyncResult BeginClose(AsyncCallback callback, object state); IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state); IAsyncResult BeginOpen(AsyncCallback callback, object state); IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state); void EndClose(IAsyncResult result); void EndOpen(IAsyncResult result); }
ICommunicationObject 的初始状态是“已创建”,此时可以配置它的各种属性。 一旦处于“已打开”状态,对象就可用于发送和接收消息,但它的属性将视为不可变。 一旦处在“正在关闭”状态,对象就不能再处理新的发送或接收请求,但在到达“关闭”超时前有可能完成现有的请求。 如果发生不可恢复的错误,则对象将转换到“出错”状态,此时可以检查该对象以获取有关错误的信息,该对象最终将关闭。 处于“已关闭”状态时,该对象实质上已到达状态机的终点。 对象一旦从一个状态转换到下一个状态,它将不会返回至前一状态,整个过程图3所示:
图 3
通道形状
每个通道均实现一个或多个接口,称为通道形状接口或通道形状。通道形状的最底层是 IChannel 接口,该接口提供一个 GetProperty<T> 方法,用作访问由通道堆栈中的通道公开的任意功能的分层机制。扩展 IChannel 的五种通道形状为:
1.IInputChannel:用于接收消息
2.IOutputChannel:用于发送消息
3.IRequestChannel:用于发送请求
4.IReplyChannel:用于发送回复
5.IDuplexChannel:用于双向消息传递
它们之间的关系如图4所示:
图 4
其实可以看出,IDuplexChannel接口是IInputChannel和IOutputChannel接口的联合,所有的通道形状都同时扩展了ICommunicationObject和IChannel。这5种通道模型分别对应于不同的消息交换模式,在使用数据报模式时,消息发送方通道实现了IOutputChannel接口,而消息接收方通道实现了IInputChannel接口;在请求响应模式中,客户端通道实现IRequestChannel接口,而服务通道实现IReplyChannel接口;在双工通信模式中,由于双方都能发送和接收消息,客户端和服务通道实现了IDuplexChannel接口,如图5所示:
图 5
服务端通道
在通道对象模型中,除了IChannel接口,另外一个接口IChannelListener用于消息的接收端,通过绑定来生成通道侦听器(在绑定中有关于协议、编码和传输的信息,关于绑定可以参考WCF专题系列(6):消息如何传递之绑定Part 1),用于侦听传入的消息。通道侦听器负责创建通道并从下面的层或者从网络接收消息,收到的消息将借助于通道侦听器所创建的通道传送到上面的层中。整个过程如图6所示:
图 6
在WCF的内部,对于消息的每一个处理(即通道堆栈中的通道),都会对应一个内部的通道侦听器,如针对事务处理的TransactionChannelListener和使用TCP传输的TcpChannelListener,分别用于创建各自对应的通道。
客户端通道
在WCF的客户端,通道的创建使用通道工厂,创建的这些通道负责获取来自上一层的消息,对消息进行必要的处理,然后将消息发送到下一层,如图7所示:
图 7
在WCF内部,同样对于消息的每一个处理,都会有相应的通道工厂,如使用TCP传输的TcpChannelFactory,用于创建对应的通道。
总结
本文详细介绍了WCF中的通道编程模型以及关于通道、通道监听器和通道工厂等,大多数都是纯理论的知识,在下一篇文章中,将会通过一个示例来加深对于本文所讲知识的认识。