Programming WCF Services 学习笔记五、Operations
1. 传统的面向对象或面向组件只提供Client到Server的一种调用方式,同步调用。WCF提供了更多的调用方式,允许Service回调Client。而且可以支持更大的负载。
2. Operation type是Service Design的一部分,而且对不同的绑定有不同的要求,且不能随意更改,所以要小心。
3. Operation Types
i. Request-Reply
1. 即传统的同步调用模型,是WCF默认的调用模型。除了NetPeerTcpBinding和NetMsmqBinding之外,所有的Binding都支持此模型。
ii. One-Way
1. One-Way属于Fir-and-forget类型。适用于Client不关心Service返回值的情况。
2. 在这种情况下,Service不能返回值给Client,Service端的异常也不能传递到Client端。
3. One-Way不等同于异步调用。(因为没有回调)
4. One-Way情况下,Client的调用到达Service端后,并不是马上被执行,而是先入队,然后依照Service端指定的调用模型执行。
5. Service的队列能容纳多少个Call发(Request-Reply和One-Way),取决于Channel和Reliability模型。当队列满时,新到来的Call会被阻塞。当Call被入队时,Client即可解除阻塞,继续执行。
6. 所有的Binding都支持One-Way。
7. 通过使用OperationContract Attribute的IsOneWay属性执行是否使用One-Way模型(默认Request-Reply)。
8. 被标记为One-Way的方法不能有返回值,否则会报异常。
9. One-Way不关心返回值并不代表One-Way不关心调用是否传达到Service并且被执行。一般情况下,应该启用可靠消息传输,保证调用被送达。
10. One-Way不使用与启用Session的Service,因为启用Session意味着Client关心Service端的状态,这与One-Way的设计意图相反。One-Way适用于PerCall和Singleton。在启用Session时使用One-Way,尽量只在IsTerminating的方法上使用One-Way。
11. 不要认为One-Way是单向的,或者是黑盒子,认为Service对Client没有任何影响。当一个One-Way Call被分配时,遇到通讯错误(错误地址等),Client端还是会引发异常的。并且Service Instance模型和Binding的不同,Service端的异常也会影响Client端。
12. 在PerCall,并不启用Transport Session时,Service端发生异常,不会影响Client端,Client可以继续执行。
13. 当启用TransPort Session时,会传递异常到Client端。
4. Callback Operations
i. WCF支持Service回调Client,此时Client和Service角色被互换了。
ii. 当回调发生时,Client可以正确地Host被回调的对象。
iii. 不是所有的Binding都支持回调。Http协议的基本Binding不支持Callback。WCF提供了WSDualHttpBingding用来支持Http协议上的Callback。(因为WSDualHttpBinding提供了两个Http Channel)。TCP和NamedPipe都支持Callback。
iv. Callback Operation是Service Contract的一部分,而且一个ServiceContract只能有一个CallbackContract。通过ServiceContract Attribute指定当前ServiceContract的CallbackContract(另一个ServiceContract,但无须加ServiceContract Attribute,此CallbackContract被引用到Client端时,名字被自动指定为“ServiceContractName+Callback”)。
v. Client端可以Host CallBack 对象,通过把CallBack实例传递给 InstanceContext类的构造函数实现。Service端可以通过OperationContext.Current取得CallBack Context。
vi. 当使用CallBack Operation时,Client端的Proxy继承自DuplexClientBase<>泛型类,并在构造函数中接受一个Callback Instance或Context。
vii. 当使用Callback Operation时,Client不会自动销毁Proxy。可以在Client中自行管理Proxy的生命周期(调用完Callback就销毁)。
viii. Service端通过OperationContext.Current.GetCallbackChannel<Callback OperationName>()调用Callback。
ix. 默认情况下,WCF是不允许Service调用Client端的Callback Operation的。因为WCF的Service是单线程的,即某一时刻只允许一个线程存取Service Instance。当Service调用Client时,会锁定当前Service Instance,而Service处理Client返回消息时,又需要同样的锁,这时就会发生死锁。
x. 处理死锁有三个办法:
1. 设置WCF Service使用多线程方式,但要涉及同步问题。
2. 设置WCF Service使用单线程,但可以接受Callback。
3. 设置Callback Service的Callback Operation为One-Way模式,即单向调用。
4. 前两种方式通过设置ServiceBehavior的ConcurrencyMode为Reentrant/Multiple。
xi. 当Service回调Client时,Client已经不存在(Closed),Service端会收到一个ObjectDisposedException异常。为了解决这个问题,把Client的Proxy的引用存储在Service端的静态属性中,但这种方法在PerCall时会遇到问题,因为PerCall模式下Service端的数据在Call结束后会丢失,所以Proxy的引用也就丢失了。使用Singleton则会出现Proxy的引用失效的问题。一个可行的办法是定义两个方法Connect和DisConnect,在没一个Call的前后分别取得Proxy和销毁Proxy的引用。
xii. PerSession模式可以通过在Instance Property中存储Proxy的引用的方法工作。但不要保存在Static Property中,否则需要加入Connect和DisConnect机制。
xiii. NetTCPBinding和NamedPpleBinding绑定不用为Callback指定端口。
xiv. WSDualHttpBinding 绑定使用两个Http 通道,所以需要制定Callback地址和端口。Callback默认使用80端口,与IIS有冲突,所以提供了clientBaseAddress指定地址和端口号。也可以在CallbackContract上加CallbackBaseAddressBehavior Attribute,使用CallbackPort属性指定回调端口。
5. Events
(待续)