IServiceBehavior接口

描述:提供一种在整个服务内修改或插入自定义拓展机制;
命名空间:  System.ServiceModel.Description
程序集:  System.ServiceModel(在 System.ServiceModel.dll 中)
 
IServiceBehavior接口中有3个方法:
      1.AddBindingParameters:该方法可以向绑定元素传递服务的自定义信息,这样绑定元素就可向服务提供正确的支持。
      2.ApplyDispatchBehavior:该方法可以更改运行时属性值或插入自定义扩展对象,例如错误处理程序、消息或参数拦截器、安全扩展以及其他自定义扩展对象。
      3.Validate:该方法可以在 WCF构造执行服务前检查说明,从而确认该执行服务是否可正确执行。
 
在上面的3个中最常用到的就是2和3,1本人还没有用过这里也就不使用了!!
 
 
方法:ApplyDispatchBehavior
 
该方法应该说是这个接口最主要的方法,我们要对服务进行自定义拓展也是通过它进行注入,下面我们举个例子使用IServiceBehavior对WCF服务异常的处理
大家都知道WCF一般是使用SAOP进行传输的,如果服务端出现异常客户端是只能够接收到FaultException异常,这里我们通过IServiceBehavior来解决使客户端可以接收到所有异常信息。
 
代码:
 
    /// <summary>
    /// WCF服务异常处理机制,服务的行为将默认的异常处理添加到所有通信的调度程序中
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
    public sealed class ServiceErrorHandlerBehavior
        : Attribute, IServiceBehavior
    {
        /// <summary>
        /// 用于更改运行时属性值或插入自定义扩展对象(例如错误处理程序、消息或参数拦截器、安全扩展以及其他自定义扩展对象)。
        /// </summary>
        /// <param name="serviceDescription"> 服务说明</param>
        /// <param name="serviceHostBase"> 当前正在生成的宿主 </param>
        public void ApplyDispatchBehavior( ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            if (serviceHostBase != null && serviceHostBase.ChannelDispatchers.Any())
            {
                foreach ( ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
                    dispatcher.ErrorHandlers.Add( new InstallErrorHandler());
            }
        }
 
        public void AddBindingParameters( ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            //当前拓展机制不适用
        }
 
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            //当前拓展机制不适用
        }
    }
从ServiceHostBase宿主中遍历通道调度程序集ChannellDispatchers合并在每个ChannelDispatcher中的ErrorHandlers插入自定义异常ServiceErrorHandler,这样的话当WCF服务出现异常时就会转交给ServiceErrorHandler处理;
下面是InstallErrorHandler代码:
 
    public class ServiceErrorHandler
        : IErrorHandler
    {
        /// <summary>
        /// 启用错误相关处理并返回一个值,该值指示调度程序在某些情况下是否中止会话和实例上下文。
        /// </summary>
        /// <param name="error">处理过程中引发的异常</param>
        /// <returns></returns>
        public bool HandleError(Exception error)
        {
            //不终止会话和实例上下文
            return true;
        }
 
        /// <summary>
        /// 启用创建从服务方法过程中的异常返回的自定义SOAP错误
        /// </summary>
        /// <param name="error">服务操作过程中引发的异常 </param>
        /// <param name="version">消息的 SOAP 版本</param>
        /// <param name="fault">双工情况下,返回到客户端或服务的通信单元对象 </param>
        public void ProvideFault( Exception error, MessageVersion version, ref Message fault)
        {
            var faultException = error is FaultException ?
                ( FaultException)error : new FaultException(error.Message);
 
            MessageFault messageFault = faultException.CreateMessageFault();
            fault = Message.CreateMessage(version, messageFault, faultException.Action);
        }
    }
 
 
下面是使用方法,非常的简单,只需要在WCF服务类上打上ServiceErrorHandlerBehavior标记就可以了:
代码:
    [ServiceErrorHandlerBehavior ]
    public class Service1 : IService1
    {
        public string GetData(int value)
        {
            throw new Exception( "我的测试");
        }
    }
测试代码:
    protected void Page_Load(object sender, EventArgs e)
    {
        WcfWrapper<ServiceReference1. Service1Client> wrapper = new WcfWrapper<ServiceReference1. Service1Client>();
        wrapper.Using(client =>
        {
            xtResult.Text = client.GetData(1);
        });
    }
输出结果:

“/”应用程序中的服务器错误。


我的测试

说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

异常详细信息: System.ServiceModel.FaultException: 我的测试

源错误:

行 114:
行 115: public string GetData(int value) {
行 116: return base.Channel.GetData(value);
行 117: }
行 118:

源文件: f:\ZcyProject\Bulrush.Library\WebTest\Service References\ServiceReference1\Reference.cs    行: 116

当然除了使用Attribute特性也可以在WebConfig中配置,配置也非常的简单;
首先为ServiceErrorHandlerBehavior创建一个Behavior的拓展配置节点,代码如下:
 
    public class ServiceErrorHandlerBehaviorExtension
        : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof( ServiceErrorHandlerBehavior); }
        }
 
        protected override object CreateBehavior()
        {
            return new ServiceErrorHandlerBehavior();
        }
    }
配置如下:
 
  <system.serviceModel>
    <services>
      < service name =" WcfServiceTest.Service1" behaviorConfiguration="defaultBehavior" >
        < endpoint address ="" binding =" basicHttpBinding" contract="WcfServiceTest.IService1" >
        </ endpoint>
        < host>
          < baseAddresses>
            < add baseAddress="http://localhost:2708/Service1.svc" />
          </ baseAddresses>
        </ host>
      </ service>
    </services>
    <behaviors>
      < serviceBehaviors>
        < behavior name =" defaultBehavior" >
          < serviceMetadata httpGetEnabled =" true" httpsGetEnabled="true"/>
          < serviceDebug includeExceptionDetailInFaults =" false" />
          < ErrorBehavior />
        </ behavior>
      </ serviceBehaviors>
    </behaviors>
    <extensions>
      < behaviorExtensions>
        < add name= "ErrorBehavior "
          type="Bulrush.WCF.Behaviors.Errors.ServiceErrorHandlerBehaviorExtension, Bulrush.WCF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
        />
      </ behaviorExtensions>
    </extensions>
  </system.serviceModel>
 
 
到这里自定义异常处理机制就已经完成了!
 
 
方法:Validate
 
该方法主要是对当前的拓展机制进行检查,主要检测两个东西ServiceDescription服务说明和ServiceHostBase服务宿主,它的返回值并不是bool类型而是void类型,所以标识它是否通用验证的方式就是是否抛出异常,抛出异常代表验证不通过。
为了演示这个方法,我们把上面的ServiceErrorHandler中的ProvideFault方法简单的修改下,修改如下:
 
        public void ProvideFault( Exception error, MessageVersion version, ref Message fault)
        {
            var faultException = error is FaultException<ServiceError> ?
                ( FaultException< ServiceError>)error :
                new FaultException< ServiceError>( new ServiceError { Message = "此操作不能在这个时刻处理。请稍后尝试。如果问题仍然存在与您的系统管理员联系" });
 
            MessageFault messageFault = faultException.CreateMessageFault();
            fault = Message.CreateMessage(version, messageFault, faultException.Action);
        }
 
这里ServiceError只是一个SOAP的传输对象,里面只有一个Message属性就不贴代码了,改成这个方式后呢,假设业务上必须让该服务的每个方法建立错误契约[FaultContract(typeof(ServiceError))],虽然不建立这个服务契约服务可以正常运行,但是所有的错误信息都是“此操作不能在这个时刻处理....”,那么就变的没有意义了,所以我们强制要求每Coder在编写服务方法是必须建立这个错误契约,这个时候我们就可以实现Validate来检查了,具体代码如下:
 
    public void Validate( ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
        bool flag = false;
 
        foreach ( var point in serviceDescription.Endpoints)
        {
            foreach ( var operation in point.Contract.Operations)
            {
                if (operation.Faults.Count == 0)
                    throw new InvalidOperationException (string .Format("使用SeriveErrorHandlerBehavior机制,必须为服务方法{0}标识 FaultContractAttribute(typeof(ServiceError)) 错误契约", operation.Name));
 
                flag = false;
                foreach ( var fault in operation.Faults)
                {
                    if (fault.DetailType.Equals(typeof(ServiceError )))
                    {
                        flag = true;
                        break;
                    }
 
                }
                if (!flag)
                {
                    throw new InvalidOperationException(string .Format("使用SeriveErrorHandlerBehavior机制,必须为服务方法{0}标识 FaultContractAttribute(typeof(ServiceError)) 错误契约", operation.Name));
                }
            }
        }
    }
 
这个时候如果服务标识了ServiceErrorHandlerBehavior拓展机制,那么下边的所有方法都必须建立错误契约,只要有一个方法没有建立错误契约这个服务就无法被链接!
    
    [ ServiceContract]
    public interface IService1
    {
        //[FaultContract(typeof(ServiceError))]
        [ OperationContract]
        string GetData( int value);
    }
 
运行服务http://localhost:2708/Service1.svc运行服务则会出现异常:

“/”应用程序中的服务器错误。


使用SeriveErrorHandlerBehavior机制,必须为服务方法GetData标识 FaultContractAttribute(typeof(ServiceError)) 错误契约

说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

异常详细信息: System.InvalidOperationException: 使用SeriveErrorHandlerBehavior机制,必须为服务方法GetData标识 FaultContractAttribute(typeof(ServiceError)) 错误契约

 
好了,就写到这里了,写博客真心不容易,感谢那些为我们提供帮助的博主们!!!!

Wcf实现IServiceBehavior拓展机制的更多相关文章

  1. 服务端增加WCF服务全局异常处理机制

    服务端增加WCF服务全局异常处理机制,任一WCF服务或接口方式出现异常,将统一调用WCF_ExceptionHandler.ProvideFault方法,因此不需要每个方法使用try catch写法. ...

  2. WCF服务全局异常处理机制

    服务端增加WCF服务全局异常处理机制,任一WCF服务或接口方式出现异常,将统一调用WCF_ExceptionHandler.ProvideFault方法,因此不需要每个方法使用try catch写法. ...

  3. 【已解决】谁动了我的CurrentPrincipal?求助我在给Artech的wcf petshop增加授权机制的时候遇到的问题。

    这个问题已解决,是绑定设置的问题,主要还是因为我自己没有深入理解WCF绑定的安全机制.在这篇博客里面我来说说怎么解决的. 下载了Artech的wcf petshop源码(博文链接)并调试运行成功后,打 ...

  4. 浅议Grpc传输机制和WCF中的回调机制的代码迁移

    浅议Grpc传输机制和WCF中的回调机制的代码迁移 一.引子 如您所知,gRPC是目前比较常见的rpc框架,可以方便的作为服务与服务之间的通信基础设施,为构建微服务体系提供非常强有力的支持. 而基于. ...

  5. 探究Dubbo的拓展机制: 上

    这篇博文是我决心深度学习Dubbo框架时记录的笔记, 主题是Dubbo的拓展点, 下面的几个部分相对来说比较零散, 貌似是不和主题挂钩的 , 并且是一些很冷门的知识点 , 但是它们确实是深入学习Dub ...

  6. 探究Dubbo的拓展机制: 下

    承接上篇, 本篇博文的主题就是认认真真捋一捋, 看一下 Dubbo是如何实现他的IOC / AOP / 以及Dubbo SPI这个拓展点的 总览: 本篇的话总体上分成两部分进行展开 第一点就是 Dub ...

  7. 搞懂Dubbo SPI可拓展机制

    前言 阅读本文需要具备java spi的基础,本文不讲java spi,please google it. 一.Dubbo SPI 简介 SPI(Service Provider Interface) ...

  8. Extending WCF using IServiceBehavior, IOperationBehavior, and IParameterInspector

    [ServiceContract(Name = "PasswordGenerator")] public interface IPasswordGenerator { [Opera ...

  9. WCF服务全局统一异常处理机制

    转载:http://www.csframework.com/archive/1/arc-1-20150109-2193.htm 服务端增加WCF服务全局异常处理机制,任一WCF服务或接口方式出现异常, ...

随机推荐

  1. 异常处理与调试5 - 零基础入门学习Delphi54

    调试(Debug) 让编程改变世界 Change the world by program [caption id="attachment_2731" align="al ...

  2. appsettings.json

    appsettings.json 目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 在我们之前的Asp.net mvc 开发中,一提到配置文件,我们不由的想到 web.conf ...

  3. 使用ARM模板部署自动扩展的Linux VMSS(1)

    在Azure之前的ASM版本或者经典模式中,用户使用Azure Website,Azure Cloud Service等PAAS服务,可以实现一定程度上的自动扩展(auto scaling),但有着诸 ...

  4. USBASP下载线制作教程

  5. Qt中事件处理的方法(三种处理方法,四种覆盖event函数,notify函数,event过滤,事件处理器。然后继续传递给父窗口。可观察QWidget::event的源码,它是虚拟保护函数,可改写)

    一.Qt中事件处理的方式   1.事件处理模式一 首先是事件源产生事件,最后是事件处理器对这些事件进行处理.然而也许大家会问, Qt中有这么多类的事件,我们怎么样比较简便的处理每个事件呢?设想,如果是 ...

  6. WPF 利用子线程弹出子窗体的研究

    一般来说子线程都是用来处理数据的,主窗体用来实现展现,但是有些时候我们希望子窗体实现等待效果,遮挡主窗体并使主窗体逻辑正常进行,这个业务需求虽然不多,但是正好我们用到了,于是我打算把研究成果写在这了. ...

  7. g++ error: extra qualification on member [-fpermissive]

    以下这段代码是在头文件里面的,DmaOpen DmaClose函数也是直接在class pcie_chip{}里面的.加了个额外的pcie_chip::才会报错. //delete pcie_chip ...

  8. 《how to design programs》第11章自然数

    这章让我明白了原来自然数的定义本来就是个递归的过程. 我们通常用枚举的方式引出自然数的定义:0,1,2,3,等等(etc).最后的等等是什么意思?唯一能把等等从描述自然数的枚举方法中去除的方法是自引用 ...

  9. LeetCode——Reverse Words in a String

    Given an input string, reverse the string word by word. For example, Given s = "the sky is blue ...

  10. 怎样查询SCI和EI检索号

    为了年终考核,花了一个早上才搞清楚,里面有非常多小问题.以下具体说明具体过程: SCI检索号 1.进入图书馆主页: 2.选择"电子数据库": 3.选择外文数据库中的"We ...