利用Attribute和IErrorHandler处理WCF全局异常
2012-10-26 18:27
393 查看
在处理WCF异常的时候,有大概几种方式:
第一种是在配置文件中,将includeExceptionDetailInFaults设置为true
第二种方法是自定义错误,通过FaultException直接指定错误信息。
第一种是在配置文件中,将includeExceptionDetailInFaults设置为true
<behaviorname="serviceDebuBehavior"><serviceDebugincludeExceptionDetailInFaults="true"/></behavior>
但是这种方式会导致敏感信息泄漏的危险,一般我们仅仅在调试的时候才开启该属性,如果已经发布,为了安全,我们一般会设置成false。
第二种方法是自定义错误,通过FaultException直接指定错误信息。
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
publicclassCalculatorService:ICalculator
{
thrownewFaultException("被除数y不能为零!");
}
但这样我们还必须为WCF的方法里显式的去抛出异常,如果能像.NET一样,在Global里直接捕获全局的异常,并写入log4net日志多好,有没有方法在wcf里如果出现异常,异常日志写入服务器断,同时抛给客户端呢?
要实现这个,需要三步
第一步:我们需要实现IErrorHandler接口,实现他的两个方法
boolHandleError(Exceptionerror);
voidProvideFault(Exceptionerror,MessageVersionversion,refMessagefault);
其中HandleError是true表示终止当前session
在ProvideFault方法里我们可以写我们要抛给客户端的自定义的错误,同时也可以在服务器端写异常日志。
我们实现一个GlobalExceptionHandler,继承自IErrorHandler,同时在ProvideFault里通过log4net写服务器端日志,如下:
namespaceWcfService
{
usingSystem;
usingSystem.ServiceModel;
usingSystem.ServiceModel.Channels;
usingSystem.ServiceModel.Dispatcher;
///<summary>
///GlobalExceptionHandler
///</summary>
publicclassGlobalExceptionHandler:IErrorHandler
{
///<summary>
///测试log4net
///</summary>
privatestaticreadonlylog4net.ILoglog=log4net.LogManager.GetLogger(typeof(GlobalExceptionHandler));
#regionIErrorHandlerMembers
///<summary>
///HandleError
///</summary>
///<paramname="ex">ex</param>
///<returns>true</returns>
publicboolHandleError(Exceptionex)
{
returntrue;
}
///<summary>
///ProvideFault
///</summary>
///<paramname="ex">ex</param>
///<paramname="version">version</param>
///<paramname="msg">msg</param>
publicvoidProvideFault(Exceptionex,MessageVersionversion,refMessagemsg)
{
////写入log4net
log.Error("WCF异常",ex);
varnewEx=newFaultException(string.Format("WCF接口出错{0}",ex.TargetSite.Name));
MessageFaultmsgFault=newEx.CreateMessageFault();
msg=Message.CreateMessage(version,msgFault,newEx.Action);
}
#endregion
}
}
第二步:现在我们需要创建一个自定义的ServiceBehaviourAttribute,让WCF知道当WCF任何异常发生的时候,我们通过这个自定义的Attribute来处理。实现这个需要继承IServiceBehavior接口,并在此类的构造函数里,我们获取到错误类型。
一旦ApplyDispatchBehavior行为被调用时,我们通过Activator.CreateInstance创建错误handler,并把这个错误添加到每个channelDispatcher中。
ApplyDispatchBehavior
channelDispatcher中文叫信道分发器,当我们的ServiceHost调用Open方法,WCF就会创建我们的多个信道分发器(ChannelDispatcher),每个ChannelDispatcher都会拥有一个信道监听器(ChannelListener),ChannelListener就有一直在固定的端口监听,等到Message的到来,调用AcceptChannel构建信道形成信道栈,开始对Message的处理。
usingSystem; usingSystem.Collections.ObjectModel; usingSystem.ServiceModel; usingSystem.ServiceModel.Channels; usingSystem.ServiceModel.Description; usingSystem.ServiceModel.Dispatcher; namespaceWcfService { publicclassGlobalExceptionHandlerBehaviourAttribute:Attribute,IServiceBehavior { privatereadonlyType_errorHandlerType; publicGlobalExceptionHandlerBehaviourAttribute(TypeerrorHandlerType) { _errorHandlerType=errorHandlerType; } #regionIServiceBehaviorMembers publicvoidValidate(ServiceDescriptiondescription, ServiceHostBaseserviceHostBase) { } publicvoidAddBindingParameters(ServiceDescriptiondescription, ServiceHostBaseserviceHostBase, Collection<ServiceEndpoint>endpoints, BindingParameterCollectionparameters) { } publicvoidApplyDispatchBehavior(ServiceDescriptiondescription, ServiceHostBaseserviceHostBase) { varhandler= (IErrorHandler)Activator.CreateInstance(_errorHandlerType); foreach(ChannelDispatcherBasedispatcherBasein serviceHostBase.ChannelDispatchers) { varchannelDispatcher=dispatcherBaseasChannelDispatcher; if(channelDispatcher!=null) channelDispatcher.ErrorHandlers.Add(handler); } } #endregion } }
第三步:在我们的WCF的类上,加上GlobalExceptionHandlerBehaviour
usingSystem; namespaceWcfService { [GlobalExceptionHandlerBehaviour(typeof(GlobalExceptionHandler))] publicclassSomeService:ISomeService { #regionISomeServiceMembers publicstringSomeFailingOperation() { thrownewException("Kaboom"); returnnull; } #endregion } }
这时候,客户端和服务器端都已经分别能记录到错误的异常日志了。
附:log4net配置
<?xmlversion="1.0"encoding="utf-8"?>
<configuration>
<configSections>
<sectionname="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler,log4net,Version=1.2.10.0,Culture=Neutral,PublicKeyToken=bf100aa01a5c2784"/>
</configSections>
<log4net>
<!--日志文件部分log输出格式的设定-->
<appendername="RollingLogFileAppender"type="log4net.Appender.RollingFileAppender">
<filevalue="./Logs\Log_"/>
<appendToFilevalue="true"/>
<rollingStylevalue="Date"/>
<datePatternvalue="yyyyMMdd'.txt'"/>
<staticLogFileNamevalue="false"/>
<layouttype="log4net.Layout.PatternLayout">
<headervalue="------------------------------------------------------------ "/>
<ConversionPatternvalue="%date[%thread]%-5level%logger[%ndc]-%message%newline%newline%newline"/>
</layout>
</appender>
<appendername="WcfService.Api_Error"type="log4net.Appender.RollingFileAppender"LEVEL="ERROR">
<filevalue="./Logs\API\logError_"/>
<appendToFilevalue="true"/>
<datePatternvalue="yyyyMMdd'.txt'"/>
<rollingStylevalue="Date"/>
<staticLogFileNamevalue="false"/>
<layouttype="log4net.Layout.PatternLayout">
<headervalue="[Header] "/>
<footervalue="[Footer] "/>
<conversionPatternvalue="%date{dd/MM/yyyy-HH:mm:ss}%m%newline%exception"/>
</layout>
<filtertype="log4net.Filter.LevelRangeFilter">
<paramname="LevelMin"value="ERROR"/>
<paramname="LevelMax"value="ERROR"/>
</filter>
</appender>
<appendername="WcfService.Api_Info"type="log4net.Appender.RollingFileAppender"LEVEL="INFO">
<filevalue="./Logs\API\logInfo_"/>
<appendToFilevalue="true"/>
<datePatternvalue="yyyyMMdd'.txt'"/>
<rollingStylevalue="Date"/>
<staticLogFileNamevalue="false"/>
<layouttype="log4net.Layout.PatternLayout">
<headervalue="[Header] "/>
<footervalue="[Footer] "/>
<conversionPatternvalue="%date{dd/MM/yyyy-HH:mm:ss}%m%newline%exception"/>
</layout>
<filtertype="log4net.Filter.LevelRangeFilter">
<paramname="LevelMin"value="INFO"/>
<paramname="LevelMax"value="INFO"/>
</filter>
</appender>
<root>
<levelvalue="All"/>
<appender-refref="RollingLogFileAppender"/>
</root>
<loggername="WcfService"additivity="false">
<appender-refref="WcfService.Api_Info"/>
<appender-refref="WcfService.Api_Error"/>
</logger>
</log4net>
</configuration>
相关文章推荐
- 利用Attribute和IErrorHandler处理WCF全局异常
- 利用Attribute和IErrorHandler处理WCF全局异常
- 利用Attribute和IErrorHandler处理WCF全局异常
- android 处理程序全局异常和错误,UncaughtExceptionHandler
- MVC 使用HandleErrorAttribute统一处理异常
- WCF全局异常处理
- MVC 全局异常过滤器HandleErrorAttribute
- @ControllerAdvice + @ExceptionHandler 全局处理 Controller 层异常
- Spring全局异常捕捉实现HandlerExceptionResolver接口,在error-page配置捕捉异常
- 【WCF】自定义错误处理(IErrorHandler接口的用法)
- PHP 的异常处理、错误处理:error_reporting,try-catch,trigger_error,set_error_handler,set_exception_handler,register_shutdown_function
- 利用UncaughtExceptionHandler捕获全局异常
- Spring MVC 全局异常处理(1) --HandlerExceptionResolver
- springMVC-异常的全局处理 @ControllerAdvice , @ExceptionHandler(Exception.class)
- Flex全局错误处理Global Error Handler代码兼容运行于低版本Flash Player
- 利用HandlerExceptionResolver对SpringMVC进行统一异常处理
- 使用spring利用HandlerExceptionResolver实现全局异常捕获
- PHP 的异常处理、错误处理:error_reporting,try-catch,trigger_error,set_error_handler,set_exception_handler,regis
- 应用Spring mvc HandlerExceptionResolver 处理异常全局跳转方法
- 服务端增加WCF服务全局异常处理机制