方法: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)) 错误契约
 
好了,就写到这里了,写博客真心不容易,感谢那些为我们提供帮助的博主们!!!!