zoukankan      html  css  js  c++  java
  • 利用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
        }
    }
  • 相关阅读:
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》内容介绍
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》前言
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》内容介绍
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》微软中国.NET Micro Framework项目组工程师所作之序
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》资源汇总
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》微软中国.NET Micro Framework项目组工程师所作之序
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》前言
    Windows、Linux、ARM、Android、iOS全平台支持的RTMP推流组件libEasyRTMP库接口调用说明
    简单高效易用Windows/Linux/ARM/Android/iOS平台实现RTMP推送组件EasyRTMPAndroid MediaCodec硬编码流程介绍
    RTSP网络监控摄像头如何实现Windows、Linux、ARM、Android、iOS全平台支持的拉RTSP流推出RTMP直播流?
  • 原文地址:https://www.cnblogs.com/wangjingblogs/p/4699455.html
Copyright © 2011-2022 走看看