Wcf实现IServiceBehavior拓展机制

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服务出现异常时就会转交给 Service ErrorHandler处理;
下面是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)) 错误契约
 
好了,就写到这里了,写博客真心不容易,感谢那些为我们提供帮助的博主们!!!!

转载于:https://www.cnblogs.com/zcylife/p/3652805.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值