Welcome

首页 / 软件开发 / WCF / WCF技术剖析之三十:一个很有用的WCF调用编程技巧[下篇]

WCF技术剖析之三十:一个很有用的WCF调用编程技巧[下篇]2012-12-07 cnblogs 蒋金楠在《上篇》中,我通过使用Delegate的方式解决了服务调用过程中的异常处理以及对服务代理的关闭。对于《WCF技术剖析(卷1)》的读者,应该会知道在第7章中我通过类似于AOP的方式解决了相似的问题,现在我们来讨论这个解决方案。

通过《服务代理不能得到及时关闭会有什么后果?》的介绍,我们知道了及时关闭服务代理的重要意义,并且给出了正确的编程方式。如果严格按照上面的编程方式,就意味着对于每一个服务调用,都要使用相同的代码进行异常处理和关闭或中断服务代理对象。按照我个人的观点,一个应用程序的每一个角落若充斥着相同的代码片断,这是一种很不好的设计。设计的目的在于实现代码的重用(Reuse),绝非代码的重复(Duplicate)

所以现在我们的目的是将重复使用的代码进行单独维护,在使用到的地方进行重用。思路是这样:通过一个对象实现对客户端进行服务访问的方法调用的劫持,在该对象的内部实现真正的方法调用、服务代理关闭或中断,以及异常处理。这实际上是一种基于AOP的解决方案,在这里通过自定义真实代理(RealProxy)的方式来实现服务调用的AOP,这也是为何在本章的开始会花如此多的笔墨介绍真实代理和透明代理的一个重要原因。

下图所示的顺序图(Sequence Diagram)揭示了具体实现的原理:在定义的RealProxy(ServiceRealProxy)中实现了服务调用、异常处理和信道关闭或中断。客户端代码进行服务调用完全是通过自定义真实代理ServiceRealProxy的透明代理进行的,所以所有的方法调用都会直接分发给ServiceRealProxy对象。ServiceRealProxy根据当前方法调用的上下文(比如参数、MethodBase等)构建ChannelFactory<T>对象并创建真正的服务代理对象。然后ServiceRealProxy借助创建出来的服务代理进行真正的服务调用,如果服务调用正常完成,则调用Close方法关闭服务代理,如果在调用过程中抛出CommunicationException和TimeoutException这两个异常,则调用Abort方法强行中断服务代理。最后,将服务调用的结果或抛出的异常通过TransparentProxy返回给客户端代码。

本例仅仅是为如何通过AOP进行WCF服务调用提供一种思路,并不是一个完备的解决方法(比如,没有考虑安全认证和客户端凭证的设置;没有考虑到双向通信和回调等),有兴趣的读者可以在此继承上进一步地完善。现在,就一步步地进行演示。

步骤一:创建ChannalFactory<T>的静态工厂:ChannelFactoryCreator

由于服务调用通过服务代理完成,而ChannelFactory<T>是服务代理的创建者,所以在这里先定义一个ChannelFactoryCreator的静态工厂类,通过它来创建或获取ChannelFactory<T>方法。由于ChannelFactory<T>的创建是一件费时的工作,为了提供更好的性能,和ClientBase<T>一样采用了ChannelFactory<T>的缓存机制(《ClientBase<T>中对ChannelFactory<T>的缓存机制》)。不过,这里的缓存机制比ClientBase<T>的实现要简单得多,ClientBase<T>通过终结点配置名称、终结点地址和回调对象三者进行缓存,这里仅仅是通过终结点配置名称进行ChannelFactory<T>的缓存,因为我们假设客户端完全使用配置的终结点进行服务调用(这也是我们推荐的使用方式)。下面是整个ChannelFactory<T>的静态工厂类的定义:

 1: using System;
2: using System.Collections;
3: using System.ServiceModel;
4: namespace Artech.ServiceProxyFactory
5: {
6: internal static class ChannelFactoryCreator
7: {
8: private static Hashtable channelFactories = new Hashtable();
9:
10: public static ChannelFactory<T> Create<T>(string endpointName)
11: {
12: if (string.IsNullOrEmpty(endpointName))
13: {
14: throw new ArgumentNullException("endpointName");
15: }
16:
17: ChannelFactory<T> channelFactory = null;
18:
19: if(channelFactories.ContainsKey(endpointName))
20: {
21: channelFactory = channelFactories[endpointName] as ChannelFactory<T>;
22: }
23:
24: if (channelFactory == null)
25: {
26: channelFactory = new ChannelFactory<T>(endpointName);
27: lock (channelFactories.SyncRoot)
28: {
29: channelFactories[endpointName] = channelFactory;
30: }
31: }
32:
33: return channelFactory;
34: }
35: }
36: }
ChannelFactoryCreator中通过一个Hashtable类型的静态变量保存所有创建出来ChannelFactory<T>集合,Hashtable的Key为表示终结点配置名称的字符串。在Create<T>方法中,先通过传入的终结点配置名称查看缓存中是否存在已经创建好的ChannelFactory<T>对象,如果存在则直接返回,否则创建新的ChannelFactory<T>对象,并在返回之前将其加入缓存。