加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

WCF技术剖析之三十:一个很有用的WCF调用编程技巧[下篇]

发布时间:2020-12-16 09:05:49 所属栏目:asp.Net 来源:网络整理
导读:在《上篇》中,我通过使用Delegate的方式解决了服务调用过程中的异常处理以及对服务代理的关闭。对于《WCF技术剖析(卷1)》的读者,应该会知道在第7章中我通过类似于AOP的方式解决了相似的问题,现在我们来讨论这个解决方案。 通过《 服务代理不能得到及时

在《上篇》中,我通过使用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;
   3: using System.ServiceModel;
   5: {
   7:     {
   9:? 
  11:         {
  13:             {
  15:             }
  17:             ChannelFactory<T> channelFactory = null;
  19:             if(channelFactories.ContainsKey(endpointName))
  21:                 channelFactory = channelFactories[endpointName] as ChannelFactory<T>;
  23:? 
  25:             {
  27:                 lock (channelFactories.SyncRoot)
  29:                     channelFactories[endpointName] = channelFactory;
  31:             }
  33:             return channelFactory;
  35:     }
  
using System.Runtime.Remoting.Proxies;
   5: namespace Artech.ServiceProxyFactory
   7:     class ServiceRealProxy<T>: RealProxy
   9:         string _endpointName;
  11:         public ServiceRealProxy(string endpointName):base(typeof(T))
  13:             string.IsNullOrEmpty(endpointName))
  15:                 "endpointName");
  17:             this._endpointName = endpointName;
  19:? 
  21:         {
  23:             IMethodCallMessage methodCall = (IMethodCallMessage)msg;
  25:             object[] copiedArgs = Array.CreateInstance(typeof(object),methodCall.Args.Length) as object[];
  27:             try
  29:                 object returnValue = methodCall.MethodBase.Invoke(channel,copiedArgs);
  31:                 (channel as ICommunicationObject).Close();
catch (Exception ex)
  35:                 if (ex.InnerException is CommunicationException || ex.InnerException is TimeoutException)
  37:                     (channel as ICommunicationObject).Abort();
  39:? 
  42:                     methodReturn = new ReturnMessage(ex.InnerException,1)" id="lnum43">  43:                 }
  45:                 {
  48:             }
  50:             return methodReturn;
  52:     }
   3: {
   5:     {
   8:                9:             {
return (T)(new ServiceRealProxy<T>(endpointName).GetTransparentProxy());
  14:     }
   1: ICalculator calculator = ServiceProxyFactory.Create<ICalculator>("calculatorservice");
   4:     Console.WriteLine("{3}: x + y = {2} when x = {0} and y = {1}",1,2,calculator.Add(1,2),i);
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次服务调用成功完成,由此可以证明每次服务调用结束后,会话信道都被成功关闭。会话信道的自动关闭或中断还带来一个好处,由于每次使用的是新信道,所以即使上一个服务调用出错,也不会影响后续的调用。下面的例子证明了这一点:

3: {
   5: }
   7: {
   9: }
The server was unable to process the request due to an internal error.  For more information about the error,either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client,or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.
?
x + y = 2 when x = 2 and y = 0
作者:Artech
出处:http://artech.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读