利用Attribute和IErrorHandler处理WCF全局异常
在处理WCF异常的时候,有大概几种方式:
第一种是在配置文件中,将includeExceptionDetailInFaults设置为true
<behavior name="serviceDebuBehavior"><serviceDebug includeExceptionDetailInFaults="true" /></behavior>
但是这种方式会导致敏感信息泄漏的危险,一般我们仅仅在调试的时候才开启该属性,如果已经发布,为了安全,我们一般会设置成false。
第二种方法是自定义错误,通过FaultException直接指定错误信息。
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class CalculatorService : ICalculator
{
throw new FaultException("被除数y不能为零!");
}
但这样我们还必须为WCF的方法里显式的去抛出异常,如果能像.NET一样,在Global里直接捕获全局的异常,并写入log4net日志多好,有没有方法在wcf里如果出现异常,异常日志写入服务器断,同时抛给客户端呢?
要实现这个,需要三步
第一步: 我们需要实现IErrorHandler接口,实现他的两个方法
bool HandleError(Exception error);
void ProvideFault(Exception error, MessageVersion version, ref Message fault);
其中HandleError是true表示终止当前session
在ProvideFault方法里我们可以写我们要抛给客户端的自定义的错误,同时也可以在服务器端写异常日志。
我们实现一个GlobalExceptionHandler ,继承自IErrorHandler,同时在ProvideFault里通过log4net写服务器端日志,如下:
namespace WcfService
{
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
/// <summary>
/// GlobalExceptionHandler
/// </summary>
public class GlobalExceptionHandler : IErrorHandler
{
/// <summary>
/// 测试log4net
/// </summary>
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(GlobalExceptionHandler));
#region IErrorHandler Members
/// <summary>
/// HandleError
/// </summary>
/// <param name="ex">ex</param>
/// <returns>true</returns>
public bool HandleError(Exception ex)
{
return true;
}
/// <summary>
/// ProvideFault
/// </summary>
/// <param name="ex">ex</param>
/// <param name="version">version</param>
/// <param name="msg">msg</param>
public void ProvideFault(Exception ex, MessageVersion version, ref Message msg)
{
//// 写入log4net
log.Error("WCF异常", ex);
var newEx = new FaultException(string.Format("WCF接口出错 {0}", ex.TargetSite.Name));
MessageFault msgFault = newEx.CreateMessageFault();
msg = Message.CreateMessage(version, msgFault, newEx.Action);
}
#endregion
}
}
第二步:现在我们需要创建一个自定义的Service Behaviour Attribute,让WCF知道当WCF任何异常发生的时候,我们通过这个自定义的Attribute来处理。实现这个需要继承IServiceBehavior接口,并在此类的构造函数里,我们获取到错误类型。
一旦ApplyDispatchBehavior行为被调用时,我们通过Activator.CreateInstance创建错误handler,并把这个错误添加到每个channelDispatcher中。
ApplyDispatchBehavior
channelDispatcher中文叫信道分发器,当我们的ServiceHost调用Open方法,WCF就会创建我们的多个信道分发器(ChannelDispatcher),每个ChannelDispatcher都会拥有一个信道监听器(ChannelListener),ChannelListener就有一直在固定的端口监听,等到Message的到来,调用AcceptChannel构建信道形成信道栈,开始对Message的处理。
using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher; namespace WcfService
{
public class GlobalExceptionHandlerBehaviourAttribute : Attribute, IServiceBehavior
{
private readonly Type _errorHandlerType; public GlobalExceptionHandlerBehaviourAttribute(Type errorHandlerType)
{
_errorHandlerType = errorHandlerType;
} #region IServiceBehavior Members public void Validate(ServiceDescription description,
ServiceHostBase serviceHostBase)
{
} public void AddBindingParameters(ServiceDescription description,
ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection parameters)
{
} public void ApplyDispatchBehavior(ServiceDescription description,
ServiceHostBase serviceHostBase)
{
var handler =
(IErrorHandler) Activator.CreateInstance(_errorHandlerType); foreach (ChannelDispatcherBase dispatcherBase in
serviceHostBase.ChannelDispatchers)
{
var channelDispatcher = dispatcherBase as ChannelDispatcher;
if (channelDispatcher != null)
channelDispatcher.ErrorHandlers.Add(handler);
}
} #endregion
}
}
第三步:在我们的WCF的类上,加上GlobalExceptionHandlerBehaviour
using System; namespace WcfService
{
[GlobalExceptionHandlerBehaviour(typeof (GlobalExceptionHandler))]
public class SomeService : ISomeService
{
#region ISomeService Members public string SomeFailingOperation()
{
throw new Exception("Kaboom");
return null;
} #endregion
}
}
这时候,客户端和服务器端都已经分别能记录到错误的异常日志了。
附:log4net配置
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net, Version=1.2.10.0, Culture=Neutral, PublicKeyToken=bf100aa01a5c2784" />
</configSections>
<log4net>
<!-- 日志文件部分log输出格式的设定 -->
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="./Logs\Log_" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd'.txt'" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<header value="------------------------------------------------------------
" />
<ConversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline%newline%newline" />
</layout>
</appender>
<appender name="WcfService.Api_Error" type="log4net.Appender.RollingFileAppender" LEVEL="ERROR">
<file value="./Logs\API\logError_" />
<appendToFile value="true" />
<datePattern value="yyyyMMdd'.txt'" />
<rollingStyle value="Date" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<header value="[Header]
" />
<footer value="[Footer]
" />
<conversionPattern value="%date{dd/MM/yyyy-HH:mm:ss} %m%newline%exception" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="ERROR" />
<param name="LevelMax" value="ERROR" />
</filter>
</appender>
<appender name="WcfService.Api_Info" type="log4net.Appender.RollingFileAppender" LEVEL="INFO">
<file value="./Logs\API\logInfo_" />
<appendToFile value="true" />
<datePattern value="yyyyMMdd'.txt'" />
<rollingStyle value="Date" />
<staticLogFileName value="false" />
<layout type="log4net.Layout.PatternLayout">
<header value="[Header]
" />
<footer value="[Footer]
" />
<conversionPattern value="%date{dd/MM/yyyy-HH:mm:ss} %m%newline%exception" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="INFO" />
<param name="LevelMax" value="INFO" />
</filter>
</appender>
<root>
<level value="All" />
<appender-ref ref="RollingLogFileAppender" />
</root>
<logger name="WcfService" additivity="false">
<appender-ref ref="WcfService.Api_Info" />
<appender-ref ref="WcfService.Api_Error" />
</logger>
</log4net>
</configuration>
利用Attribute和IErrorHandler处理WCF全局异常的更多相关文章
- WCF全局异常处理
在用wcf做为单纯的服务端的时候,发生错误是常有的事情,特别是在调用其他系统提供的接口的时候,发生的一些错误总是让人摸不着头脑,严重影响了错误的定位.做.net web开发的时候,我们可以在Globa ...
- Net Core集成Exceptionless分布式日志功能以及全局异常过滤
Net Core集成Exceptionless分布式日志功能以及全局异常过滤 相信很多朋友都看过我的上篇关于Exceptionless的简单入门教程[asp.Net Core免费开源分布式异常日志收集 ...
- 使用spring利用HandlerExceptionResolver实现全局异常捕获
最近一直没有时间更新是因为一直在更新自己使用的框架. 之后会慢慢带来对之前使用的spring+mvc+mybatis的优化. 会使用一些新的特性,实现一些新的功能. 我会尽量分离业务,封装好再拿出来. ...
- Android全局异常捕获
PS:本文摘抄自<Android高级进阶>,仅供学习使用 Java API提供了一个全局异常捕获处理器,Android引用在Java层捕获Crash依赖的就是Thread.Uncaught ...
- Springboot项目全局异常统一处理
转自https://blog.csdn.net/hao_kkkkk/article/details/80538955 最近在做项目时需要对异常进行全局统一处理,主要是一些分类入库以及记录日志等,因为项 ...
- SpringBoot图文教程15—项目异常怎么办?「跳转404错误页面」「全局异常捕获」
有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1-Spr ...
- 在C#代码中应用Log4Net(四)在Winform和Web中捕获全局异常
毕竟人不是神,谁写的程序都会有bug,有了bug不可怕,可怕的是出错了,你却不知道错误在哪里.所以我们需要将应用程序中抛出的所有异常都记录起来,不然出了错,找问题就能要了你的命.下面我们主要讨论的是如 ...
- MVC 好记星不如烂笔头之 ---> 全局异常捕获以及ACTION捕获
public class BaseController : Controller { /// <summary> /// Called after the action method is ...
- spring设置全局异常处理器
1.spring设置全局异常,它的原理是向上捕获 spring.xml配置 <!--自定义全局异常处理器--> <bean id="globalExceptionResol ...
随机推荐
- JS省市区联动效果
省市区联动下拉效果在WEB中应用非常广泛,尤其在电商网站最为常见.一般使用Ajax实现无刷新下拉联动.利用jQuery,通过读取JSON数据,实现无刷新动态下拉省市二(三)级联动效果. 首先我们可以看 ...
- anaconda使用以及创建python3.7+pytorch1.0虚拟环境以及Jupyter notebook初级使用
查看所有已安装的软件包$ conda list# packages in environment at S:\Users\jiangshan\Anaconda3:## Name Version Bui ...
- Arduino入门笔记(3):单LED闪烁
转载请注明:@小五义http://www.cnblogs.com/xiaowuyi 欢迎加入讨论群 64770604 在搭建好arduino开发环境(http://www.cnblogs.com/xi ...
- linux 文件夹和文件操作
1.统计目录有多少个文件数 find ./company -type f | wc -l 2.删除文件夹中的文件 rm -f * #最经典的方法,删除当前目录下的所有类型的文件 rsync --del ...
- 如何在ASP.NET Core中构造UrlHelper,及ASP.NET Core MVC路由讲解
参考文章: Unable to utilize UrlHelper 除了上面参考文章中介绍的方法,其实在ASP.NET Core MVC的Filter拦截器中要使用UrlHelper非常简单.如下代码 ...
- 分裂 BZOJ2064 状压DP
分析: 这个题很好啊,比起什么裸的状压DP高多了! 我们可以考虑,什么时候答案最大:全合并,之后再分裂 这样,我们必定可以得到答案,也就是说答案必定小于n+m 那么我们可以考虑,什么时候能够使答案更小 ...
- CM (Cloudera Manager) 的安装,便于CDH的离线部署
一.准备工作 主机个数:n台 操作系统:CentOS 6.5 安装所需软件包: CM: cloudera-manager-el6-cm5.4.3_x86_64.tar.gz CDH parcel: C ...
- 20155206赵飞 Exp1PC平台逆向破解及Bof基础实践
实验一 逆向及Bof基础 1.掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码 NOP汇编指令的机器码是"90" JNE汇编指令的机器码是"75" ...
- 汇编 ADD指令
知识点: 加法汇编指令ADD 一.加法指令 ADD(Addition) 格式 格式: ADD A,B //A=A+B; 功能: 两数相加 . OPRD1为任一通用寄存器或存储器操作数,可以是任意一个 ...
- Centos7下python3安装pip-9.0.1
pip类似RedHat里面的yum,安装Python包非常方便.本节详细介绍pip的安装.以及使用方法 1.下载pip安装包 [root@localhost ~]# wget https://pypi ...