您的位置:首页 > 其它

利用Attribute和IErrorHandler处理WCF全局异常

2012-10-26 18:27 393 查看
在处理WCF异常的时候,有大概几种方式:

第一种是在配置文件中,将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>


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
章节导航