四、WCF架构
1. WCF架构的关键元素及其概念
Contracts and Description
Contracts定义消息系统的各个方面,包括Data Contract,Message Contract,Service Contract。Data Contract是WCF中Service与Client之间用来交换的数据的格式定义,它采用Xml架构定义语言(XSD)来定义,使得Service和Client都能理解数据格式定义。消息协定能定义消息的特定部分,默认情况下,WCF的消息是固定格式的,但某些情况下,也可以使用Message Contract来自定义消息格式。
Service Runtime
在服务运行时,是在服务实际运行时候的一些行为控制。ErrorBehavior是在服务出现错误的时候发生的操作。ThrottingBehavior能够限制创建多少个实例和会话,通过这个你能够控制WCF服务的性能。MetaBehavior控制是否和如何向外部提供元数据。TransactionBehavior能定义事务性,使得当发生异常的时候能进行回滚。DispatchBehavior能控制WCF处理消息的方式,通过扩展性功能可以自定义运行时进程。
Messaging
在WCF中,消息是在通道(Channel)中进行传递的。通道是以某种方式对消息进行处理的组件。一组通道可以组合成“通道堆栈”,主要有两大通道:协议通道和传输通道。协议通道说明数据的格式和交换模式,WS-Security是对在消息层启用安全性的WS-Security规范的实现。通过WS-Reliable Messaging通道可以保证消息的传递,编码器提供了大量的编码,可使用这些编码来满足消息的需要。HTTP通道指定应使用超文本传输协议来传递消息。同理,TCP通道指定TCP协议,事务流通道控制已经过事务处理的消息模式。通过命名管道通道可以进行进程间通信,使用MSMQ通道可以与MSMQ应用程序进行互操作。
Activation and Hosting
WCF服务的最终形式仍然是程序,它能够“自承载”,也可以寄宿到其它应用程序之中,如IIS,Windows服务,Com+等。
五、消息交换模式
1.WCF定义的消息交换模式
One-Way Calls
在这种交换模式中,有着如下的特征:
1)没有返回值,返回类型只能为void。
2)不能包含ref或者out类型的参数。
3)只有客户端发起请求,服务端并不会对请求进行回复。
通过设备OperationContract的IsOneWay = True可以将满足要求的方法设置为这种消息交换模式。
注意:如果Test方法的返回类型不是void或者带有ref或者out类型的参数,都会抛出异常InvalidOperationException.
Request/Reply
它是缺省的消息交换模式,类似于http协议中的请求/响应模式。
这种交换模式是使用最多的一种,有如下特征:
1)调用服务方法后需要等待服务的消息返回,即便该方法返回void类型。
2)相比Duplex来说,这种模式强调的是客户端的被动接收,也就是说客户端接收到响应后,消息交换就结束了。
3)在这种模式下,服务端永远是服务端,客户端就是客户端,职责分明。
这是缺省的消息交换模式,放置OperationContract便可以设置为此种消息交换模式
注意:尽管Test方法返回为void,但Server也会生成relpy响应并发送给Client。
Duplex
它和request/reply模式类似,但处理过程却比request/reply要复杂,因为它可以在处理完请求之后,通过请求客户端中的回调进行响应操作。
1)消息交换过程中,服务端和客户端角色会发生调换。
2)服务端处理完请求后,返回给客户端的不是reply,而是callback请求。
Duplex模式对Binding有特殊的要求,它要求支持Duplex MEP(Message Exchange Pattern),如WSDualHttpBinding和NetTcpBinding。
五、事件广播
1.实现一个基于duplex的事件广播
1)通过调用服务端的Accept(),客户端能连接上服务端,并保持会话。
2)客户端在启动的时候,可以通过远程调用GetJobs()来获取当前服务端中全部的任务,并将这些任务在客户端窗体中用列表控制呈现出来。
3)客户端能通过调用AddJob()向服务端添加任务,当服务端完成添加操作之后,引发添加完成的事件,并向全部的客户端广播该事件。
4)当客户端服务端发来的添加新任务事件广播的时候,客户端将新增任务添加到列表控件加以呈现。
5)客户端可以命令服务端执行具体某个任务,当任务在开始执行和执行结束后,服务端都会像全部客户端广播任务的执行情况,并且任务的执行和事件的广播异步执行。
6)客户端收到广播后,便可以更新任务信息。
2.实现duplex事件广播中的几个问题
1)Duplex模式对服务行为ConcurrencyMode的要求
ConcurrencyMode是控制服务并发的,默认情况下ConcurrencyMode的值为Single,它设置服务运行在单线程下,当上一个请求未完成之前,服务是不接受下一个请求。而duplex在进行回调的时候,如果回调方法没有被设置为one-way的交换模式,服务端是会等待客户端对回调的响应的,这可不是一件好事情,因为服务端并不能保证客户端能正常地执行回调并返回数据。更多的情况下,我们期望回调在发出后能立即返回,方法有两个:a.将回调方法设置为one-way交换模式。b.采用多线程。当回调方法被设置了one-way模式后,将ConcurrencyMode设置为Single是可以实现duplex又向通讯的。要第二种方法也非常简单,只需要将ConcurrencyMode设置为Mutiple,此时即使回调方法不是one-way模式,也是可以完成duplex的。值得说明一下的是ConcurrencyMode还有中性的属性:ConcurrencyMode.Reentrant,能实现在单线程下同时接受多个请求,但有利必有弊,它不能保证请求事务的完整性,使用的时候应该谨慎。
2)InstanceContextMode = InstanceContextMode.PerSession能实现广播
如果将InstanceContextMode设置为PerSession,我们知道服务端对象是针对每一个会话的,也就是说每个会话会产生一个对象实例,这样如果要实现广播,我们必须将当前服务包含的会话信息用一个列表对象记录下来,广播的时候,我们会遍历会话列表,进行每个回调。
3)会话过期
会话过期后,通讯会被中止,解决方法是通过设置OperationContract的IsTerminating来实现会话的维护,当一个OperationContract的IsTerminating被设置为false的时候,该操作不会导致会话的中断。
六、实例模式和对象生命周期
1.WCF的实例模式
WCF的实例模式分为三种:PerSession, PerCall, Single
PerCall
1)客户端创建代理对象(Proxy)。
2)客户端调用代理对象的一个契约操作,代理对象将其传递给服务宿主程序。
3)宿主应用程序创建一新的服务契约对象,并且执行请求操作。
4)在执行完请求操作后,如果要求有应答,那么服务契约会给代理对象一个应答,然后销毁自己(如果实现了IDisposable,则调用Dispose())。
PerSession
1)客户端创建代理对象(Proxy)。
2)客户端第一次调用代理对象的一个契约操作,代理对象将其调用请求传递给服务宿主。
3)宿主程序创建新的服务对象,并执行请求操作,如果有必要,返回客户端应答。
4)客户端再次发出调用操作的请求,宿主会先判断是否已有建立好的会话,如果存在,则不需要再创建新的服务对象,直接使用老对象即可。
5)在时间达到指定要求或者因一些特殊原因,会话会过期,此时服务对象销毁。
Single
1)服务端启动,同时创建服务对象。
2)客户端通过代理调用契约操作。
3)创建的服务对象接受请求,并执行操作,进行必要的应答。
4)创建的服务对象将一直保留。
5)服务关闭,创建的对象销毁。
2.各种实例模式的应用场合
PerCall
当一个请求操作来到的时候,再创建服务对象,申请必要资源,而当操作完毕之后,立即销毁对象并释放资源,留给下一个请求。这就可能大大提高服务端的吞吐能力,而且WCF中默认的实例创建模式就是这种。
PerSession
PerSession能在服务端和客户端维护状态,当一个服务对象创建之后不会马上销毁,而是等待客户端再次来消费它。它能够保持连接和维护状态,这在要求有回调的情况下特别重要。另一种情况,服务端操作不需要比较多的资源或者占用的资源也不宝贵的情况下,而却与客户端在不同的网络中,它们之间进行一次连接可费了老劲,这时也适用于些种实例模式。
Single
Single模式下服务对象只创建一次,类似Singleton设计模式。
3.使用不同的实例模式的注意事项
PerCall
对于PerCall模式,如果服务对象中的数据没有固化,并且不是静态变量,那它每次操作都会被重新初始化。
PerSession
对于PerSession模式,第一要清楚有些binding是不能用于此种模式的,另外,PerSession模式并不是代表阙云太会自动维护,那些被设置了IsTerminating=True的操作完成的时候,也会释放资源和销毁对象,即使不是True,那如果客户端长时间不与服务端联系达到服务端最大忍耐限度,服务端会话也会超时。
Single
对于Single模式,能保持服务对象中的非静态全局变量。但要特别注意线程安全的问题。