利用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>

时间: 2024-10-13 02:59:30

利用Attribute和IErrorHandler处理WCF全局异常的相关文章

Spring 框架——利用HandlerExceptionResolver实现全局异常捕获

https://blog.csdn.net/qq_22172133/article/details/82147630 微信一.需求描述        因为在项目中,我们不可否认的会出现异常,而且这些异常并没有进行捕获.经常出现的bug如空指针异常等等.在之前的项目中,如果我们没有进行任何配置,那么容器会自动打印错误的信息,如果tomcat的404页面,400页面等等.如果我们在web.xml中进行如下配置,就会拦截错误,然后跳转到指定的错误页面. <error-page>    <err

利用ASP.NET MVC Filter 处理网站异常

1,Filter(筛选器)是基于AOP(面向方面编程)的设计,他的好处什么的就不是本文要说的,如果要了解关于filter的相关知识请参照,大神说的够清楚了:http://www.cnblogs.com/willick/p/3331520.html 这里主要记录一下我自己的利用ASP.NET MVC Filter 处理网站异常过程: 2,首先添加 一个自定义的filter类: using System; using System.Collections.Generic; using System.

Android全局异常捕捉

// 定义自定义捕捉 package com.xiaosw.test; import java.io.File; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.Thread.UncaughtExceptionHandler;

MVC异常处理的7大场景 + MVC的异常处理的过滤器 + 全局异常

1.MVC中捕获异常的过滤器属性时[HandleError] 2. 可以扩展这个属性来捕获异常 3.注册这个过滤器 4.Mvc的异常捕获时:Filter + 全局异常捕获 5.异常处理的7大场景 /// <summary> /// 异常处理在MVC中可以用过滤器属性[HandleError]实现--->利用Aop扩展这个属性 /// /// 自定义异常处理--标记到方法---出现异常惠静如Filter---完成善后处理 /// /// /// 全局注册的异常处理的Filter,7大场景会

.net Log4Net日志的配置及使用 全局异常过滤器

.net添加Log4Net日志的配置及使用,以及将其设置为全局异常过滤器,主要有以下步骤: 1. 新建一个Web应用程序2. 引用log4net.dll3. 添加config文件4. 在AssemblyInfo.cs进行注册5. 在Global.asax中进行初始化设置6. 添加Log4Helper.cs帮助类7. 新增过滤器LogExceptionFilter.cs文件8. 在FilterConfig.cs中添加过滤器9. 在Global.asax中注册过滤器 详细步骤如下: 1.新建一个we

爱上MVC~业务层刻意抛出异常,全局异常的捕获它并按格式返回

对于业务层的程序的致命错误,我们一直的做法就是直接抛出指定的异常,让程序去终断,这种做法是对的,因为如果一个业务出现了致命的阻塞的问题,就没有必要再向上一层一层的返回了,但这时有个问题,直接抛异常,意味着服务器直接500了,前端如何去显示,或者如果你是API的服务,如果为前端返回,如果是500,那直接就挂了,哈哈! 下面是在MVC环境下优化的全局异常捕获代码(非API) /// <summary> /// 全局异常捕获 /// </summary> public class Glo

Asp.net Core WebApi 全局异常类

通过全局异常类,所有程序中遇到的错误都会被拦截,并友好的返回结果. 1.自定义一个全局异常处理类中间件 using Microsoft.AspNetCore.Http; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; using Syst

利用Apperance协议定义View的全局外观

假设要定义一个全局的bkColor用于背景颜色 [email protected](nonatomic,strong)UIColor *bkColor UI_APPEARANCE_SELECTOR; 2.在下面方法中定义默认的背景颜色bkColr = redcolor; +(void)initialize{ [CustomView appearance].bkColor = [UIColor redColor]; } 3.在set方法里面设置backgroundColor: - (void)se

springmvc中拦截器与springmvc全局异常处理器的问题

最近在做一个练手的小项目, 系统架构中用了springmvc的全局异常处理器, 做了系统的统一异常处理. 后来加入了springmvc的拦截器, 为了一些需求, 在拦截器中的 preHandle 方法 中抛出了系统自定义异常, 当时有有个疑惑, 就是抛出的这个异常全局异常处理器怎么处理的. 这里的全局异常处理器时通过实现HandlerExceptionResolver这个借口实现的 要指出的是 resolveException方法 中 handler中代表的是什么,我没遇到这个问题之前我认为这玩