WCF全局异常处理_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > WCF全局异常处理

WCF全局异常处理

 2013/10/9 16:01:00  先秦剑仙  博客园  我要评论(0)
  • 摘要:在用wcf做为单纯的服务端的时候,发生错误是常有的事情,特别是在调用其他系统提供的接口的时候,发生的一些错误总是让人摸不着头脑,严重影响了错误的定位。做.netweb开发的时候,我们可以在Global里面直接捕获全局异常,那么wcf是否也可以定义全局异常处理?对于已有的系统,逐个方法添加异常处理是很不现实而且还会伴随很大的风险,那么我们肯定希望这种改动尽可能的小甚至不用改动。下面分享一下实现的方法:利用Attribure和IServiceBehavior实现wcf全局异常处理这种方式使用方便
  • 标签:WCF 异常处理 全局 异常

 

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

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

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

class="code_img_closed" src="/Upload/Images/2013100916/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('82740ecc-1db5-4379-b067-8a3f2e4d42b5',event)" src="/Upload/Images/2013100916/2B1B950FA3DF188F.gif" alt="" />
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         

可参考利用Attribute和IErrorHandler处理WCF全局异常
 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

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

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

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

 

发表评论
用户名: 匿名