Wcf自定义错误处理机制

对于Wcf的异常处理,已经有些文章讲得很好了.

基础性的文章:老徐的错误契约与异常处理.

以及Artech的扩展应用文章.

Enterprise Library深入解析与灵活应用(8):WCF与Exception Handling AppBlock集成[上] 

Enterprise Library深入解析与灵活应用(8):WCF与Exception Handling AppBlock集成[下]

  最近在搞个基于.net 4的开发应用.在实际的应用中Wcf自身的错误控制开关<serviceDebug includeExceptionDetailInFaults="true"/>,一般在发布时需要关闭在关闭后不利用异常的捕捉.而且传递出的并不一定是真正的错误异常.这个是错误处理改进的最大原因了.当然.不想在接口契约加上FaultContract属性也是出于开发方便的想法,我承认我懒.

  异常都是通过消息传递到客户端的,在何处捕捉异常就决定了采用何种方式.所幸Wcf为我们做了很多. 错误处理接口:IErrorHandler,围绕着这个接口来实现自定义方式.

  1. 异常明细封装,引用Artech文章中的类定义,其中.FaultAction进行了调整,原因在后说明.代码如下:
    ExpandedBlockStart.gif 代码
        [DataContract(Namespace  =   " http://www.artech.com/ " )]
        
    public   class  ServiceExceptionDetail : ExceptionDetail
        {
            
    public   const   string  FaultSubCodeNamespace  =   @" http://www.artech.com/exceptionhandling/ " ;
            
    public   const   string  FaultSubCodeName  =   " ServiceError " ;
            
    public   const   string  FaultAction  =   @" http://www.w3.org/2005/08/addressing/soap/fault " ;

            [DataMember]
            
    public   string  AssemblyQualifiedName {  get private   set ; }

            [DataMember]
            
    public   new  ServiceExceptionDetail InnerException {  get private   set ; }

            
    public  ServiceExceptionDetail(System.Exception ex)
                : 
    base (ex)
            {
                
    this .AssemblyQualifiedName  =  ex.GetType().AssemblyQualifiedName;
                
    if  ( null   !=  ex.InnerException)
                {
                    
    this .InnerException  =   new  ServiceExceptionDetail(ex.InnerException);
                }
            }

            
    public   override   string  ToString()
            {
                
    return   this .Message;
            }
        }


  2. IErrorHandler实现.代码也引自Artech,代码如下:
    ExpandedBlockStart.gif ServiceErrorHandler
         public   class  ServiceErrorHandler : IErrorHandler
        {
            
    public  ServiceErrorHandler()
            {
            }

            
    #region  IErrorHandler 成员
            
    public   bool  HandleError(System.Exception error)
            {
                
    return   false ;
            }
            
    public   void  ProvideFault(System.Exception error, System.ServiceModel.Channels.MessageVersion version,  ref  System.ServiceModel.Channels.Message fault)
            {
                
    if  ( typeof (FaultException).IsInstanceOfType(error))
                {
                    
    return ;
                }
                
    try
                {                
                    fault 
    =  BuildFault(version, error);
                }
                
    catch  (System.Exception ex)
                {
                    fault 
    =  BuildFault(version, ex);
                }
            }

            
    private  Message BuildFault(System.ServiceModel.Channels.MessageVersion version,System.Exception error)
            {
                ServiceExceptionDetail exceptionDetail 
    =   new  ServiceExceptionDetail(error);
                FaultCode fc 
    =  FaultCode.CreateSenderFaultCode(ServiceExceptionDetail.FaultSubCodeName, ServiceExceptionDetail.FaultSubCodeNamespace);
                FaultException
    < ServiceExceptionDetail >  fe  =   new  FaultException < ServiceExceptionDetail > (exceptionDetail,  new  FaultReason(error.Message), fc, ServiceExceptionDetail.FaultAction);
                MessageFault msgfa 
    =  fe.CreateMessageFault();
                
    return  Message.CreateMessage(version, msgfa, fe.Action);
            }
            
    #endregion
        }

 

   3.  扩展服务端及客户端终结点行为,本方法比较多.可基于多种接口.我是采用了继承IEndpointBehavior接口.并配置文件配置behaviorConfiguration属性来控

    制.在服务端通过ApplyDispatchBehavior方法加入自定义的消息检查和错误处理类,客户端为ApplyClientBehavior方法.
   

ExpandedBlockStart.gif 服务端
public   void  ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(
new  ServiceDispatchMessageInspector());            
            
// 错误处理模块
            endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add( new  ServiceErrorHandler());            
        }
ExpandedBlockStart.gif 客户端
public   void  ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(
new  ClientMessageInspector());            
        }

 4.  通过扩展终结点行为.服务端已经能对异常封装,并通过消息发送到客户端了.客户端安全检查配置会影响到消息是否能正常接收.请注意一个配置binding节点中 <security mode="None"></security>,如果该设置不要求,那恭喜你,省事了.在第1点提到的FaultAction你可随便设置.如果该设置有特殊要求,那也就是为何

FaultAction要特殊设置的原因了.我设置了其他值,结果在客户端都会得到一个 CommunicationException异常,(注:在接口契约加入 FaultContract也可解决,但我通过程序方式在ServicePiont的Fault集合加入FaultDescription,该方式也失败),而我将Action设置为代码中的值时,也就是默认 FaultException的Action值时.结果的通过了检查. 让我非常无语.我没有再去看安全性检查所涉及的内容.FaultException中Action的产生更让我担心些,不知跟哪些有关联.知道的请告诉我一下.
   5. 我选择在客户端自定义的消息检查类的AfterReceiveReply方法中执行检查.代码如下:
ExpandedBlockStart.gif 代码
public   void  AfterReceiveReply( ref  System.ServiceModel.Channels.Message reply,  object  correlationState)
        {            
            
if  (reply.Headers.Action  ==  ServiceExceptionDetail.FaultAction)
            {
                MessageFault fault 
=  MessageFault.CreateFault(reply,  int .MaxValue);
                
if  (fault.Code.SubCode.Name  ==  ServiceExceptionDetail.FaultSubCodeName  &&
                    fault.Code.SubCode.Namespace 
==  ServiceExceptionDetail.FaultSubCodeNamespace)
                {
                    FaultException
< ServiceExceptionDetail >  exception  =  (FaultException < ServiceExceptionDetail > )FaultException.CreateFault(fault,  typeof (ServiceExceptionDetail));
                    
throw  GetException(exception.Detail);
                }
            }
        }

  这样.基本的一套异常处理已经完成.对于无法序列化的异常.采用的是抛出错误信息的方式.尽量保留了原错误信息.至于要记录Log.在相应的方法上补允也就可以完成了.很抱歉,没有将实例单独的代码放出来,有些限制.但主要是将在自定义异常处理中一些心得定出来罢.

 

转载于:https://www.cnblogs.com/platoli/archive/2011/02/18/1958016.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值