调用wcf:WCF技术剖析的 3十:一个很有用的WCF调用编程窍门技巧[下篇]

上篇我通过使用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返回给客户端代码

clip_image002

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

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

1: using ;

2: using .Collections;

3: using .ServiceModel;

4: Artech.ServiceProxyFactory

5: {

6: ernal ChannelFactoryCreator

7: {

8: private Hashtable channelFactories = Hashtable;

9: 

10: public ChannelFactory<T> Create<T>( endpoName)

11: {

12: (.IsNullOrEmpty(endpoName))

13: {

14: throw ArgumentNullException("endpoName");

15: }

16: 

17: ChannelFactory<T> channelFactory = null;

18: 

19: (channelFactories.ContainsKey(endpoName))

20: {

21: channelFactory = channelFactories[endpoName] as ChannelFactory<T>;

22: }

23: 

24: (channelFactory null)

25: {

26: channelFactory = ChannelFactory<T>(endpoName);

27: lock (channelFactories.SyncRoot)

28: {

29: channelFactories[endpoName] = channelFactory;

30: }

31: }

32: 

33: channelFactory;

34: }

35: }

36: }



ChannelFactoryCreator中通过个Hashtable类型静态变量保存所有创建出来ChannelFactory<T>集合HashtableKey为表示终结点配置名称在ChannelFactory<T>思路方法中先通过传入终结点配置名称查看缓存Cache中是否存在已经创建好ChannelFactory<T>对象如果存在则直接返回否则创建新ChannelFactory<T>对象,并在返回的前将其加入缓存Cache

步骤 2:创建自定义RealProxy:ServiceRealProxy<T> ServiceRealProxy<T>实现了真正服务、异常处理和对服务代理关闭或中断ServiceRealProxy<T>构造参数endpoName表示用于服务而采用终结点配置名称在Invoke中先借助于ChannelFactoryCreator获得ChannelFactory<T>创建服务代理对象然后通过解析参数msg(表示对思路方法)获得思路方法参数并在try控制块中通过反射传入参数服务代理对象相应思路方法从而实现了对服务对于正常服务结果将其封装成.Runtime.Remoting.Messaging.ReturnMessage对象并在返回的前Close思路方法关闭服务代理

在catch控制块中对抛出异常进行处理由于是通过反射方式实现思路方法得到异常类型基本上都是.Reflection.TargetInvocationException真正进行服务异常被作为捕获异常内部异常(InnerException)所以我们会判断内部异常是否为CommunicationException或TimeoutException来决定是否通过Abort思路方法强行中断服务代理捕获异常被封装成ReturnMessage对象返回

1: using ;

2: using .Runtime.Remoting.Messaging;

3: using .Runtime.Remoting.Proxies;

4: using .ServiceModel;

5: Artech.ServiceProxyFactory

6: {

7: public ServiceRealProxy<T>: RealProxy

8: {

9: private _endpoName;

10: 

11: public ServiceRealProxy( endpoName):base(typeof(T))

12: {

13: (.IsNullOrEmpty(endpoName))

14: {

15: throw ArgumentNullException("endpoName");

16: }

17: this._endpoName = endpoName;

18: }

19: 

20: public override IMessage Invoke(IMessage msg)

21: {

22: T channel = ChannelFactoryCreator.Create<T>(this._endpoName).CreateChannel;

23: IMethodCallMessage methodCall = (IMethodCallMessage)msg;

24: IMethodReturnMessage methodReturn = null;

25: object copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object;

26: methodCall.Args.CopyTo(copiedArgs, 0);

27: try

28: {

29: object Value = methodCall.MethodBase.Invoke(channel, copiedArgs);

30: methodReturn = ReturnMessage(Value, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall);

31: (channel as ICommunicationObject).Close;

32: }

33: catch (Exception ex)

34: {

35: (ex.InnerException is CommunicationException || ex.InnerException is TimeoutException)

36: {

37: (channel as ICommunicationObject).Abort;

38: }

39: 

40: (ex.InnerException != null)

41: {

42: methodReturn = ReturnMessage(ex.InnerException, methodCall);

43: }

44:

45: {

46: methodReturn = ReturnMessage(ex, methodCall);

47: }

48: }

49: 

50: methodReturn;

51: }

52: }

53: }



步骤 3:创建自定义服务代理工厂:ServiceProxyFactory 在本案例中对于最终客户端代码来说它利用是上面创建自定义真实代理透明代理间接地进行服务而该透明代理就是客户端服务代理为了便于编程在这里我们定义个服务代理静态工厂类:ServiceProxyFactory

1: using ;

2: Artech.ServiceProxyFactory

3: {

4: public ServiceProxyFactory

5: {

6: public T Create<T>( endpoName)

7: {

8: (.IsNullOrEmpty(endpoName))

9: {

10: throw ArgumentNullException("endpoName");

11: }

12: (T)( ServiceRealProxy<T>(endpoName).GetTransparentProxy);

13: }

14: }

15: }



步骤 4:通过ServiceProxyFactory创建服务代理进行服务 由于重复繁琐工作已经在ServiceRealProxy<T>中完成所以客户端进行服务代码将会变得很简洁为了验证在每次完毕后是否如我们所愿将信道关闭我们将ServiceProxyFactory应用到我们熟悉计算服务例子(终结点calculatorservice配置绑定类型为WsHttBinding)

1: ICalculator calculator = ServiceProxyFactory.Create<ICalculator>("calculatorservice");

2: for ( i = 1; i < 2000; i)

3: {

4: Console.WriteLine("{3}: x + y = {2} when x = {0} and y = {1}", 1, 2, calculator.Add(1, 2), i);

5: }



输出结果:

1 : x + y = 3 when x = 1 and y = 2

2 : x + y = 3 when x = 1 and y = 2

......

1999: x + y = 3 when x = 1 and y = 2

2000: x + y = 3 when x = 1 and y = 2



从输出结果可以看出2000次服务成功完成由此可以证明每次服务结束后会话信道都被成功关闭会话信道自动关闭或中断还带来个好处由于每次使用是新信道所以即使上个服务出错也不会影响后续下面例子证明了这点:

1: ICalculator calculator = ServiceProxyFactory.Create<ICalculator>("calculatorservice");

2: try

3: {

4: Console.WriteLine("x / y = {2} when x = {0} and y = {1}",2,0,calculator.Divide(2,0));

5: }

6: catch(Exception ex)

7: {

8: Console.WriteLine(ex.Message);

9: }

10: Console.WriteLine("x + y = {2} when x = {0} and y = {1}",2,0,calculator.Add(2,0));



输出结果:

The server was unable to process the request due to an ernal error. For more information about the error, either turn _disibledevent=> 

x + y = 2 when x = 2 and y = 0



作者:Artech
出处:http://artech.cnblogs.com
本文版权归作者和博客园共有欢迎转载但未经作者同意必须保留此段声明且在文章页面明显位置给出原文连接否则保留追究法律责任权利
Tag标签: WCF,Exception Handling,AOP,RealProxy,TransparentProxy
Tags:  wcf编程 调用wcf

延伸阅读

最新评论

发表评论