WCF全局异常处理
在用wcf做为单纯的服务端的时候,发生错误是常有的事情,特别是在调用其他系统提供的接口的时候,发生的一些错误总是让人摸不着头脑,严重影响了错误的定位。做.net web开发的时候,我们可以在Global里面直接捕获全局异常,那么wcf是否也可以定义全局异常处理?对于已有的系统,逐个方法添加异常处理是很不现实而且还会伴随很大的风险,那么我们肯定希望这种改动尽可能的小甚至不用改动。下面分享一下实现的方法:
利用Attribure和IServiceBehavior实现wcf全局异常处理
这种方式使用方便,基本不用改动原有的代码,效果如下:
[WcfGlobalExceptionOpreationBehaviorAttribute(typeof(WcfGlobalErrorHandler))]
public class DemoService : IDemoService
{
}
或者
[WcfGlobalServiceInterceptor]
public class DemoService : IDemoService
{
}
以上的两种方式在具体实现上稍有不同,具体实现方式如下:
在此之前先来看看IServiceBehavior接口提供的方法
public interface IServiceBehavior
{
void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters);
void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase);
void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase);
}
后面我们用到的是方法ApplyDispatchBehavior,这个方法会在服务Open的时候执行,我们可以在此注入我们自定义的异常处理程序,从而达到处理全局异常的目的(注:试验证明在服务Open之后再注入分发行为是无效的)。
形式一:IErrorHandler
private readonly Type _errorHandlerType;
public WcfGlobalExceptionOpreationBehaviorAttribute(Type handlerType)
{
_errorHandlerType = handlerType;
} /// <summary>
/// 注入自定义异常处理程序
/// </summary>
/// <param name="serviceDescription"></param>
/// <param name="serviceHostBase"></param>
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
var handler = (IErrorHandler) Activator.CreateInstance(_errorHandlerType);
foreach (ChannelDispatcher dis in serviceHostBase.ChannelDispatchers)
{
dis.ErrorHandlers.Add(handler);
}
}
原理就是我们为信道分发器注入自定义的ErrorHandler
/// <summary>
/// WCF全局异常处理
/// </summary>
public class WcfGlobalErrorHandler:IErrorHandler
{
/// <summary>
/// 启用错误相关处理并返回一个值
/// </summary>
/// <param name="ex"></param>
/// <returns>是否终止会话和上下文</returns>
public bool HandleError(System.Exception ex)
{
WcfGlobalEventHelper.FireException(new WcfGlobalException(ex.Message,ex.StackTrace,null,null));
return true;
} public void ProvideFault(System.Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
{ } }
形式二:IOperationBehavior
public class WcfGlobalOperationInterceptorAttribute:Attribute,IOperationBehavior
{
private string operationMethod; public WcfGlobalOperationInterceptorAttribute(string methodName)
{
this.operationMethod = methodName;
} public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{ } public void ApplyClientBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
{ } public void ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
{
IOperationInvoker invoke = dispatchOperation.Invoker;
dispatchOperation.Invoker = CreateInvoker(invoke);
} public void Validate(OperationDescription operationDescription)
{ } protected OperationInvoker CreateInvoker(IOperationInvoker oldInvoker)
{
return new OperationInvoker(oldInvoker, this.operationMethod);
}
}
实际上就是在ApplyDispatchBehavior方法中分发操作的Invoker进行了封装
/// <summary>
/// 使用消息提取的对象以及参数数组,并利用对该对象调用方法,然后返回该方法的返回值和输出参数
/// </summary>
public class OperationInvoker:IOperationInvoker
{
private string operationMethod;//方法名称
private IOperationInvoker invoker;//原invoker
private Stopwatch sw;//用于计时 public OperationInvoker(IOperationInvoker oldInvoker, string operationMethod)
{
this.invoker = oldInvoker;
this.operationMethod = operationMethod;
sw = new Stopwatch();
} public object[] AllocateInputs()
{
return this.invoker.AllocateInputs();
}
/// <summary>
/// 从一个实例和输入对象的集合返回一个对象和输出对象的集合
/// </summary>
/// <param name="instance"></param>
/// <param name="inputs"></param>
/// <param name="outputs"></param>
/// <returns></returns>
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
this.PreInvoke(instance, inputs);
object returnValue = null;
object invokeValue;
object[] objArray = new object[];
System.Exception ex = null;
try
{
invokeValue = this.invoker.Invoke(instance, inputs, out objArray);
returnValue = invokeValue;
outputs = objArray;
}
catch (System.Exception e)
{
ex = e;
returnValue = null;
outputs = null;
}
finally
{
this.PostInvoke(instance,returnValue,objArray,ex);
}
return returnValue;
} public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
this.PreInvoke(instance,inputs);
return this.invoker.InvokeBegin(instance, inputs, callback, state);
} public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
object returnValue = null;
object invokeValue;
object[] objArray = new object[];
System.Exception ex = null;
try
{
invokeValue = this.invoker.InvokeEnd(instance,out outputs,result);
returnValue = invokeValue;
outputs = objArray;
}
catch (System.Exception e)
{
ex = e;
returnValue = null;
outputs = null;
}
finally
{
this.PostInvoke(instance, returnValue, objArray, ex);
}
return returnValue;
} public bool IsSynchronous
{
get { return this.invoker.IsSynchronous; }
} private void PreInvoke(object instance, object[] inputs)
{
sw.Start();
} private void PostInvoke(object instane, object returnValue, object[] outputs, System.Exception ex)
{
this.sw.Stop();
if (ex == null)//没有发生异常
{
WcfGlobalInvocation invocation = new WcfGlobalInvocation(instane,this.operationMethod,this.sw.ElapsedMilliseconds);
WcfGlobalEventHelper.FireInvocation(invocation);
}
else //发生异常
{
WcfGlobalException we = new WcfGlobalException(ex.Message, ex.StackTrace, instane, this.operationMethod);
WcfGlobalEventHelper.FireException(we);
throw ex;
}
}
}
这种形式下我们就可以对原有的方法执行过程try.catch,捕获其中的异常。另外此种方式还有一个作用,就是可以监控wcf方法的执行时长,可用于发现服务的性能瓶颈。
其中这两种都用到一个类WcfGlobalEventHelper
public delegate void WcfGlobalInvocationEventHandler(WcfGlobalInvocation invocation);
public class WcfGlobalEventHelper
{
//发生异常时
private static EventHandlerList listExceptionHandler = new EventHandlerList();
private static readonly object keyException = new object(); //未发生异常时
private static EventHandlerList listInvocationHandler = new EventHandlerList();
private static readonly object keyInvocation = new object(); /// <summary>
/// wcf方法发生异常时触发该事件
/// </summary>
public static event WcfGlobalExceptionEventHandler OnGlobalExceptionExec
{
add { listExceptionHandler.AddHandler(keyException, value); }
remove { listExceptionHandler.RemoveHandler(keyException, value); }
} public static void FireException(WcfGlobalException ex)
{
var handler = (WcfGlobalExceptionEventHandler)listExceptionHandler[keyException];
if(handler != null)
{
handler(ex);
}
}
/// <summary>
/// wcf方法调用成功是触发该事件
/// </summary>
public static event WcfGlobalInvocationEventHandler onGlobalInvocationExec
{
add { listInvocationHandler.AddHandler(keyInvocation,value);}
remove { listInvocationHandler.RemoveHandler(keyInvocation,value);}
} public static void FireInvocation(WcfGlobalInvocation invocation)
{
var handler = (WcfGlobalInvocationEventHandler) listInvocationHandler[keyInvocation];
if (handler != null)
{
handler(invocation);
}
}
}
通过这个类将异常以事件的形式抛出,在服务启动之前为其注册异常处理方法即可。我们一般是发生错误时发送邮件到开发者,这样开发者可以第一时间了解系统的异常,并能快速定位到发生异常的方法以及了解异常产生的大致原因。
下面是示例的完整代码,希望对有需要的朋友有用。这也是本人第一次写博客,有不当的地方还请各位海涵。
http://files.cnblogs.com/icewater506/WcfGlobalException.7z
WCF全局异常处理的更多相关文章
- 服务端增加WCF服务全局异常处理机制
服务端增加WCF服务全局异常处理机制,任一WCF服务或接口方式出现异常,将统一调用WCF_ExceptionHandler.ProvideFault方法,因此不需要每个方法使用try catch写法. ...
- WCF服务全局异常处理机制
服务端增加WCF服务全局异常处理机制,任一WCF服务或接口方式出现异常,将统一调用WCF_ExceptionHandler.ProvideFault方法,因此不需要每个方法使用try catch写法. ...
- mvc自定义全局异常处理
异常信息处理是任何网站必不可少的一个环节,怎么有效显示,记录,传递异常信息又成为重中之重的问题.本篇将基于上篇介绍的html2cancas截图功能,实现mvc自定义全局异常处理.先看一下最终实现效果: ...
- 在.NET Core程序中设置全局异常处理
以前我们想设置全局异常处理只需要这样的代码: AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.UnhandledExc ...
- springMvc全局异常处理
本文中只测试了:实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器 对已有代码没有入侵性等优点,同时,在异常处理时能获取导致出现异常的对象,有利于提 ...
- WCF初探-12:WCF客户端异常处理
前言: 当我们打开WCF基础客户端通道(无论是通过显式打开还是通过调用操作自动打开).使用客户端或通道对象调用操作,或关闭基础客户端通道时,都会在客户端应用程序中出现异常.而我们知道WCF是基于网络的 ...
- MVC 全局异常处理及禁用显示头
MVC网站的global.asax中的Application_Start方法里,有这样一段代码: public class MvcApplication : System.Web.HttpApplic ...
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]
原文:WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇] 在[上篇]中,我们分别站在消息交换和编程的角度介绍了SOAP Fault和FaultException异常.在服务执行过 ...
- WCF技术剖析之二十一:WCF基本异常处理模式[下篇]
原文:WCF技术剖析之二十一:WCF基本异常处理模式[下篇] 从FaultContractAttribute的定义我们可以看出,该特性可以在同一个目标对象上面多次应用(AllowMultiple = ...
随机推荐
- 解决android studio设置版本号
获取版本号代码 /** * 获取版本号 * @return 当前应用的版本号 */ public static String getVersion(Context context) { try { P ...
- 校内选拔I题题解 构造题 Codeforces Round #318 [RussianCodeCup Thanks-Round] (Div. 2) ——D
http://codeforces.com/contest/574/problem/D Bear and Blocks time limit per test 1 second memory limi ...
- HDOJ4550 卡片游戏 随便销毁内存的代价就是wa//string类的一些用法
思路 标记最小的最后的位置 放在第一位 标记位置之前按left值小的左方大的右方 标记位置之后按顺序放在最后 不多说先贴上销毁内存的wa代码 销毁内存的wa代码 #include<cstdio ...
- 第009课 gcc和arm-linux-gcc和MakeFile
from:第009课 gcc和arm-linux-gcc和MakeFile 第001节_gcc编译器1_gcc常用选项_gcc编译过程详解 gcc的使用方法 gcc [选项] 文件名 gcc常用选项 ...
- 【C语言项目】贪吃蛇游戏(下)
目录 00. 目录 07. 游戏逻辑 7.5 按下ESC键结束游戏 7.6 判断是否撞到墙 7.7 判断是否咬到自己 08. 游戏失败界面设计 8.1 游戏失败界面边框设计 8.2 撞墙失败界面 8. ...
- helm istio k8s docker
helm https://hub.helm.sh/ k8s https://www.kubernetes.org.cn/k8s istio 微服务 https://istio.io/
- 题解 P1189 SEARCH
(传送门)[https://www.luogu.org/problemnew/show/P1189] 先反省一波:我以后再也不用getchar()+scanf了(日常爆零) 算是比较裸的搜索吧,在下用 ...
- js函数式编程(三)-compose和pointFree
compose即函数嵌套组合 组合compose在第一篇已经初见端倪,可以感受一下.compose函数的实现用闭包的方法.不完善实现如下: const compose = (f, g) => { ...
- awk纯干货
AWK的惊人表现: Awk设计的目的:简化一般文本处理的工作. 属于POSIX的一部分. AWK命令行: Awk的调用可以定义变量.提供程序并且指定输入文件: Awk [ -F fs ] [ -v ...
- 学习笔记(_huaji_)
假如我没有见过太阳,我也许会忍受黑暗. 如果我知道自己会在哪里死去,我就永远都不去那儿.失败的经历,其实也有它的价值. 人的过失会带来错误,但要制造真正的灾难还得用计算机. 嘴角微微上扬已不复当年轻狂 ...