zoukankan      html  css  js  c++  java
  • WCF全局异常处理

          在用wcf做为单纯的服务端的时候,发生错误是常有的事情,特别是在调用其他系统提供的接口的时候,发生的一些错误总是让人摸不着头脑,严重影响了错误的定位。做.net web开发的时候,我们可以在Global里面直接捕获全局异常,那么wcf是否也可以定义全局异常处理?对于已有的系统,逐个方法添加异常处理是很不现实而且还会伴随很大的风险,那么我们肯定希望这种改动尽可能的小甚至不用改动。下面分享一下实现的方法:

          利用Attribure和IServiceBehavior实现wcf全局异常处理

     这种方式使用方便,基本不用改动原有的代码,效果如下:

    1 [WcfGlobalExceptionOpreationBehaviorAttribute(typeof(WcfGlobalErrorHandler))]
    2     public class DemoService : IDemoService
    3     { 
    4     }
    View Code

    或者

    1 [WcfGlobalServiceInterceptor]
    2     public class DemoService : IDemoService
    3     {
    4     }
    View Code

    以上的两种方式在具体实现上稍有不同,具体实现方式如下:
    在此之前先来看看IServiceBehavior接口提供的方法

    1 public interface IServiceBehavior
    2     {
    3         void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters);
    4         void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase);
    5         void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase);
    6     }

    后面我们用到的是方法ApplyDispatchBehavior,这个方法会在服务Open的时候执行,我们可以在此注入我们自定义的异常处理程序,从而达到处理全局异常的目的(注:试验证明在服务Open之后再注入分发行为是无效的)。

    形式一:IErrorHandler         

     1 private readonly Type _errorHandlerType;
     2         public WcfGlobalExceptionOpreationBehaviorAttribute(Type handlerType)
     3         {
     4             _errorHandlerType = handlerType;
     5         }
     6 
     7         /// <summary>
     8         /// 注入自定义异常处理程序
     9         /// </summary>
    10         /// <param name="serviceDescription"></param>
    11         /// <param name="serviceHostBase"></param>
    12         public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    13         {
    14             var handler = (IErrorHandler) Activator.CreateInstance(_errorHandlerType);
    15             foreach (ChannelDispatcher dis in serviceHostBase.ChannelDispatchers)
    16             {
    17                 dis.ErrorHandlers.Add(handler);
    18             }
    19         }
    View Code

    原理就是我们为信道分发器注入自定义的ErrorHandler

     1 /// <summary>
     2     /// WCF全局异常处理
     3     /// </summary>
     4     public class WcfGlobalErrorHandler:IErrorHandler
     5     {
     6         /// <summary>
     7         /// 启用错误相关处理并返回一个值
     8         /// </summary>
     9         /// <param name="ex"></param>
    10         /// <returns>是否终止会话和上下文</returns>
    11         public bool HandleError(System.Exception ex)
    12         {
    13             WcfGlobalEventHelper.FireException(new WcfGlobalException(ex.Message,ex.StackTrace,null,null));
    14             return true;
    15         }
    16 
    17         public void ProvideFault(System.Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
    18         {
    19             
    20         }
    21 
    22     }
    View Code

     形式二:IOperationBehavior

     1     public class WcfGlobalOperationInterceptorAttribute:Attribute,IOperationBehavior
     2     {
     3         private string operationMethod;
     4 
     5         public WcfGlobalOperationInterceptorAttribute(string methodName)
     6         {
     7             this.operationMethod = methodName;
     8         }
     9 
    10         public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    11         {
    12             
    13         }
    14 
    15         public void ApplyClientBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
    16         {
    17             
    18         }
    19 
    20         public void ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
    21         {
    22             IOperationInvoker invoke = dispatchOperation.Invoker;
    23             dispatchOperation.Invoker = CreateInvoker(invoke);
    24         }
    25 
    26         public void Validate(OperationDescription operationDescription)
    27         {
    28             
    29         }
    30 
    31         protected OperationInvoker CreateInvoker(IOperationInvoker oldInvoker)
    32         {
    33             return new OperationInvoker(oldInvoker, this.operationMethod);
    34         }
    35     }
    View Code

    实际上就是在ApplyDispatchBehavior方法中分发操作的Invoker进行了封装

      1 /// <summary>
      2     /// 使用消息提取的对象以及参数数组,并利用对该对象调用方法,然后返回该方法的返回值和输出参数
      3     /// </summary>
      4     public class OperationInvoker:IOperationInvoker
      5     {
      6         private string operationMethod;//方法名称
      7         private IOperationInvoker invoker;//原invoker
      8         private Stopwatch sw;//用于计时
      9 
     10         public OperationInvoker(IOperationInvoker oldInvoker, string operationMethod)
     11         {
     12             this.invoker = oldInvoker;
     13             this.operationMethod = operationMethod;
     14             sw = new Stopwatch();
     15         }
     16 
     17         public object[] AllocateInputs()
     18         {
     19             return this.invoker.AllocateInputs();
     20         }
     21         /// <summary>
     22         /// 从一个实例和输入对象的集合返回一个对象和输出对象的集合
     23         /// </summary>
     24         /// <param name="instance"></param>
     25         /// <param name="inputs"></param>
     26         /// <param name="outputs"></param>
     27         /// <returns></returns>
     28         public object Invoke(object instance, object[] inputs, out object[] outputs)
     29         {
     30             this.PreInvoke(instance, inputs);
     31             object returnValue = null;
     32             object invokeValue;
     33             object[] objArray = new object[0];
     34             System.Exception ex = null;
     35             try
     36             {
     37                 invokeValue = this.invoker.Invoke(instance, inputs, out objArray);
     38                 returnValue = invokeValue;
     39                 outputs = objArray;
     40             }
     41             catch (System.Exception e)
     42             {
     43                 ex = e;
     44                 returnValue = null;
     45                 outputs = null;
     46             }
     47             finally
     48             {
     49                 this.PostInvoke(instance,returnValue,objArray,ex);
     50             }
     51             return returnValue;
     52         }
     53 
     54         public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
     55         {
     56             this.PreInvoke(instance,inputs);
     57             return this.invoker.InvokeBegin(instance, inputs, callback, state);
     58         }
     59 
     60         public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
     61         {
     62             object returnValue = null;
     63             object invokeValue;
     64             object[] objArray = new object[0];
     65             System.Exception ex = null;
     66             try
     67             {
     68                 invokeValue = this.invoker.InvokeEnd(instance,out outputs,result);
     69                 returnValue = invokeValue;
     70                 outputs = objArray;
     71             }
     72             catch (System.Exception e)
     73             {
     74                 ex = e;
     75                 returnValue = null;
     76                 outputs = null;
     77             }
     78             finally
     79             {
     80                 this.PostInvoke(instance, returnValue, objArray, ex);
     81             }
     82             return returnValue;
     83         }
     84 
     85         public bool IsSynchronous
     86         {
     87             get { return this.invoker.IsSynchronous; }
     88         }
     89 
     90         private void PreInvoke(object instance, object[] inputs)
     91         {
     92             sw.Start();
     93         }
     94 
     95         private void PostInvoke(object instane, object returnValue, object[] outputs, System.Exception ex)
     96         {
     97             this.sw.Stop();
     98             if (ex == null)//没有发生异常
     99             {
    100                 WcfGlobalInvocation invocation = new WcfGlobalInvocation(instane,this.operationMethod,this.sw.ElapsedMilliseconds);
    101                 WcfGlobalEventHelper.FireInvocation(invocation);
    102             }
    103             else //发生异常
    104             {
    105                 WcfGlobalException we = new WcfGlobalException(ex.Message, ex.StackTrace, instane, this.operationMethod);
    106                 WcfGlobalEventHelper.FireException(we);
    107                 throw ex;
    108             }
    109         }
    110     }
    View Code

    这种形式下我们就可以对原有的方法执行过程try.catch,捕获其中的异常。另外此种方式还有一个作用,就是可以监控wcf方法的执行时长,可用于发现服务的性能瓶颈。

    其中这两种都用到一个类WcfGlobalEventHelper

     1 public delegate void WcfGlobalInvocationEventHandler(WcfGlobalInvocation invocation);
     2     public  class WcfGlobalEventHelper
     3     {
     4         //发生异常时
     5         private static EventHandlerList listExceptionHandler = new EventHandlerList();
     6         private static readonly object keyException = new object();
     7 
     8         //未发生异常时
     9         private static EventHandlerList listInvocationHandler = new EventHandlerList();
    10         private static readonly object keyInvocation = new object();
    11 
    12         /// <summary>
    13         /// wcf方法发生异常时触发该事件
    14         /// </summary>
    15         public static event WcfGlobalExceptionEventHandler OnGlobalExceptionExec
    16         {
    17             add { listExceptionHandler.AddHandler(keyException, value); }
    18             remove { listExceptionHandler.RemoveHandler(keyException, value); }
    19         }
    20 
    21         public static void FireException(WcfGlobalException ex)
    22         {
    23             var handler = (WcfGlobalExceptionEventHandler)listExceptionHandler[keyException];
    24             if(handler != null)
    25             {
    26                 handler(ex);
    27             }
    28         }
    29         /// <summary>
    30         /// wcf方法调用成功是触发该事件
    31         /// </summary>
    32         public static event WcfGlobalInvocationEventHandler onGlobalInvocationExec
    33         {
    34             add { listInvocationHandler.AddHandler(keyInvocation,value);}
    35             remove { listInvocationHandler.RemoveHandler(keyInvocation,value);}
    36         }
    37 
    38         public static void FireInvocation(WcfGlobalInvocation invocation)
    39         {
    40             var handler = (WcfGlobalInvocationEventHandler) listInvocationHandler[keyInvocation];
    41             if (handler != null)
    42             {
    43                 handler(invocation);
    44             }
    45         }
    46     }
    View Code

     通过这个类将异常以事件的形式抛出,在服务启动之前为其注册异常处理方法即可。我们一般是发生错误时发送邮件到开发者,这样开发者可以第一时间了解系统的异常,并能快速定位到发生异常的方法以及了解异常产生的大致原因。

    下面是示例的完整代码,希望对有需要的朋友有用。这也是本人第一次写博客,有不当的地方还请各位海涵。

    https://files.cnblogs.com/icewater506/WcfGlobalException.7z

  • 相关阅读:
    觅踪8
    觅踪7
    团队开发进度报告1
    团队计划会议
    团队nabcd卡片制作及小组讨论
    团队项目NABCD
    软件需求分析
    团队电梯演讲视频
    团队开篇博客
    团队简介
  • 原文地址:https://www.cnblogs.com/icewater506/p/3358976.html
Copyright © 2011-2022 走看看