2012-01-06 91 views
3

因此,我試圖在我的WCF服務中使用Enterprise Library爲我執行一些與異常相關的工作。使用自定義異常處理程序拋出FaultException EL WCF

我的想法是爲「NullReferenceException」設置一個「自定義異常處理程序」,並在「自定義異常處理程序」中創建FaultException異常。

我的理解是,這個「新」異常會使它跨越網絡,我會在客戶端捕獲它。

更好地瞭解一些代碼:

WCF服務:

[ServiceContract(Name="MyService", ConfigurationName="MyNamespace.MyService")] 
    [ExceptionShielding("PolicyName")] 
    public interface IMyService 
    { 
     [OperationContract] 
     [FaultContract(typeof(MyFaultContract))] 
     string Method(String Param); 
} 

public class MyService : IMyService 
    { 
     public string Method(String Param) 
     { 
      throw new NullReferenceException("code-created null message here"); 
     } 
} 

定義異常處理程序:(企業庫)

public class MyExceptionHandler : IExceptionHandler 
    { 
     public MyExceptionHandler(NameValueCollection collection) { } 

     public MyExceptionHandler() { } 

     public System.Exception HandleException(System.Exception exception, 
           Guid handlingInstanceId) 
     { 
       MyFaultContract details = new MyFaultContract(); 
       if (exception is NullReferenceException) 
       { 
        details.ErrorCode = MyFaultCode.NullReferenceException; 
        details.OriginalMessage = exception.Message; 
        details.MyMessage = "Null Reference exception here!"; 
       } 
       return new FaultException<MyFaultContract>(details); 
      } 
} 
映射的NullReferenceException

應用程序配置文件中的「自定義異常處理程序「:

<exceptionPolicies> 
     <add name="PolicyName"> 
     <exceptionTypes> 
      <add name="NullReferenceException" type="System.NullReferenceException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
      postHandlingAction="ThrowNewException"> 
      <exceptionHandlers> 
       <add type="MyExceptionHandler, MyApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 
       name="MyExceptionHandler" /> 
      </exceptionHandlers> 
      </add> 
     </exceptionTypes> 
     </add> 
    </exceptionPolicies> 

而這預計將趕上這的FaultException終於客戶端代碼:

MyService.MyServiceClient client = new MyService.MyServiceClient(); 
      client.Open(); 
      try 
      { 
       string result = client.Method(string parameter); 
      } 

      catch (System.ServiceModel.FaultException<MyService.MyFaultContract> ex) 
      { 
       // where I think exception should end up 
      } 
      catch (System.ServiceModel.FaultException ex) 
      { 
       // general FaultException 
      } 

而是我得到的ProtocolException,指出答覆需要採取行動:操作接收

回覆消息「方法'採取行動''。 但是,您的客戶端代碼需要採取行動 'http://tempuri.org/MyService/MethodResponse'。

我在做什麼錯?是否有可能在「自定義異常處理程序」中返回(不顯式拋出)具有自定義FaultContract的FaultException?

任何意見表示讚賞。

更新: 正如你所看到的,後處理,在「自定義異常處理程序」操作設置爲「ThrowNewException」。 如果我將它更改爲「NotifyRethrow」,我不會再聲稱「ProtocolException」了! 而是,客戶端捕獲常規「FaultException」(不是自定義類型)。

現在的問題是爲什麼原始的自定義類型的FaultException不能通過電線。

更新2 我忘了提到的一件事是,我的WCF服務運行在ServiceHost中,而不是在IIS下。所以基本上我有一個Windows服務創建一個ServiceHost並通過這個ServiceHost暴露Service1接口。

我認爲這可能與此問題有關的原因是Enterprise Library聲稱它處理整個應用程序中的異常,而不僅僅是在服務範圍內。也許這會導致異常被拋出太晚?還是不在正確的水平?

更新3
感謝您的職位! 你是對的,我弄亂自定義處理程序的唯一原因是因爲我想設置MyFaultCode的值。 我試過你的建議 - 配置了2個處理程序。

首先是自定義處理程序並捕獲NullReference異常。它比使用MyFaultContract字段引發新的異常 - MyApplicationException。

然後,我配置了第二個處理程序 - 內置的「Fault Contract Exception Handler」,它捕獲MyApplicationException,創建新的FaultException並自動將MyApplicationException中的MyFaultcontract映射到新創建的FaultException。

WCF客戶端仍捕獲通用的FaultException,而不是定製合同。

回答

2

我會考慮使用自定義WCF IErrorHandler實現。它提供了一個集中處理服務方法中發生的所有未處理的異常的地方。

在我看來,它比使用Ent Lib更清潔,少1依賴,並且你不需要在你的配置中的錯誤映射,所以更少的XML。

例子:

public class MyServiceErrorHandler : IErrorHandler 
{ 
    /// <summary> 
    /// Central error handling for WCF services. 
    /// Whenever a service encounteres an unhandled exception, it will end up here. 
    /// This method will log the error and continue with normal error processing. 
    /// </summary> 
    /// <param name="error">The unhandled exception thrown from a service method.</param> 
    /// <returns>true if the exceptions has been handled, false if normal error processing should continue. This implementation will always return false.</returns> 
    public virtual bool HandleError(Exception error) 
    { 
     return false; // returning false so that WCF will still process the exception as usual. 
    } 

    /// <summary> 
    /// Create a custom Fault message to return to the client. 
    /// </summary> 
    /// <param name="error">The Exception object thrown in the course of the service operation.</param> 
    /// <param name="version">The SOAP version of the message.</param> 
    /// <param name="fault">The Message object that is returned to the client, or service, in the duplex case.</param> 
    public virtual void ProvideFault(Exception error, MessageVersion version, ref Message fault) 
    { 
     //If it's a FaultException already, then we have nothing to do 
     if (error is FaultException) 
      return; 

     // pack the exception info into the Fault Contract 
     MyFaultContract details = new MyFaultContract(); 
     if (exception is NullReferenceException) 
     { 
      details.ErrorCode = MyFaultCode.NullReferenceException; 
      details.OriginalMessage = error.Message; 
      details.MyMessage = "Null Reference exception here!"; 
     } 
     var faultException = new FaultException<MyFaultContract>(details); 

     // turn the fault contract into the response WCF Message. 
     var messageFault = faultException.CreateMessageFault(); 
     fault = Message.CreateMessage(version, messageFault, faultException.Action); 
    } 
} 

當然,如果你有其他的理由要使用耳鼻喉科庫中,然後繼續前進。你可以把它們連在一起。

這個鏈接也有錯誤處理一些良好的閱讀,包括添加自定義IErrorHandler行爲:http://www.codeproject.com/KB/WCF/WCFErrorHandling.aspx

+0

感謝您指出此解決方案。我試了一下,它似乎做了我現在需要的。它真的感覺......低水平。我的意思是你正抓住當異常試圖通過線路並執行一些邏輯的時刻。對其他團隊成員來說可能不完全透明,但肯定會做我需要的。再次感謝! – iEddie 2012-01-12 15:01:45

0

我打算讓這個註釋,但它得到了太久。

你看過使用異常處理塊異常屏蔽與故障合同異常處理程序嗎?我認爲它大部分都是你想要的。 http://msdn.microsoft.com/en-us/library/ff953192(v=PandP.50).aspx

該方法將創建您自己的處理程序,以將所有屬性映射到您的自定義異常類型。然後配置FaultContractExceptionHandler以將異常中的屬性映射到故障合同中的屬性。

如果你不需要爲MyFaultCode設置一個值,你可以避免一起寫一個自定義處理程序。

+0

你說得對,我弄亂自定義處理程序的唯一原因是因爲我想設置MyFaultCode的值。 所以這裏是我的2哈登勒: 首先是一個自定義處理程序,並捕獲NullReference異常。它比使用MyFaultContract字段引發新的異常MyApplicationException。 第二個處理程序 - 內置的「Fault Contract Exception Handler」捕獲MyApplicationException,自動創建新的FaultException和**將MyFaultcontract從MyApplicationException映射到新創建的FaultException。 WCF客戶端仍捕獲通用FaultException,而不是定製合同。 – iEddie 2012-01-11 15:18:26

+0

@iEddie:內置的Fault Contract Exception Handler是否像你想要的那樣工作?即是拋出一個FaultException而不是FaultException ? – 2012-01-11 15:42:22

+0

那麼,如果我只使用內置的Fault Contract Exception Handler - 是的。所以,我明確地拋出MyApplicationException,並在EL中配置了Fault Contract Exception Handler來捕獲MyApplicationException並將其轉換爲FaultException 。在這種情況下 - 是的,一切工作正常。但是我希望我的自定義FaultException具有填充的FaultCode字段,並且它似乎不像標準映射(EL GUI映射接口)有辦法在新的異常中設置固定值,只將值從一個異常對象傳遞到另一個異常對象。 – iEddie 2012-01-12 14:59:04