2013-05-02 119 views
2

我有一個定義FaultContract一個WCF服務:WCF故障異常沒有被傳播到客戶端

[OperationContract] 
[FaultContract(typeof(InvalidOperationException))] 
[FaultContract(typeof(NotSupportedException))] 
[FaultContract(typeof(Exception))] 
GetSysIdsResponse GetSysIds(string id); 

的WCF服務發現了一個特殊的情況下(空指針異常),並拋出我的FaultException:

try 
     { 
      .... 
     }   } 
     catch (InvalidOperationException ex) 
     { 
      // The specified DirectoryEntry is not a container 
      throw new FaultException<InvalidOperationException>(ex); 
     } 
     catch (NotSupportedException ex) 
     { 
      // Search is not supported by the provider that is being used 
      throw new FaultException<NotSupportedException>(ex); 
     } 
     catch (Exception ex) 
     { 
      throw new FaultException<Exception>(ex); 
     } 

它拋出最後一個。事情是,它永遠不會到達客戶端。首先,「錯誤合同作爲服務元數據的一部分發布。」在添加服務引用後,我沒有在客戶端元數據中看到它。 這是客戶端代碼。它從來沒有命中catch catch catch(FaultException e) 它只是說FaultException是用戶未捕獲的。它確實捕獲了CommunicationException。我不知道我做錯了什麼?

try 
       { 
        response = client.GetSysIds("sgentil"); 
       } 
       catch (FaultException<Exception> e) 
       { 
        Console.WriteLine("FaultException<Exception>: " + e.Detail); 
        client.Abort(); 
        return; 
       } 
       catch (FaultException e) 
       { 
        Console.WriteLine("FaultException: " + e.Message); 
        client.Abort(); 
        return; 
       } 
       catch (CommunicationException ex) 
       { 
        Console.WriteLine("CommunicationsException"); 
        client.Abort(); 
        return; 
       } 

**我嘗試的第一個答案的方法,並定義了兩個例外:

[DataContract] 
    public class SystemFault 
    { 
     [DataMember] 
     public string SystemOperation { get; set; } 
     [DataMember] 
     public string SystemReason { get; set; } 
     [DataMember] 
     public string SystemMessage { get; set; } 
    } 

    [DataContract] 
    public class DatabaseFault 
    { 
     [DataMember] 
     public string DbOperation { get; set; } 
     [DataMember] 
     public string DbReason { get; set; } 
     [DataMember] 
     public string DbMessage { get; set; } 
    } 

我然後應用它:

[FaultContract(typeof(SystemFault))] 
     GetSysIdsResponse GetSysIds(string id); 

然後把它:

catch (Exception ex) 
      { 
       SystemFault sf = new SystemFault 
        { 
         SystemOperation = "GetSystemIds", 
         SystemMessage = "Exception while obtaining AD user properties", 
         SystemReason = ex.Message 
        }; 
       throw new FaultException<SystemFault>(sf); 
      } 

客戶端現在看到系統故障類型,並具有元數據:

catch(FaultException<SystemFault> sf) 
       { 
        Console.WriteLine("SystemFault {0}: {1}\n{2}", 
         sf.Detail.SystemOperation, sf.Detail.SystemMessage, 
         sf.Detail.SystemReason); 
       } 

但仍然執行的服務器在該行停止:

throw new FaultException<SystemFault>(sf); 

它說: FaultException'1不能由用戶代碼來處理現在

什麼?

+0

當您在Visual Studio中運行時指的是「執行在服務器中停止」嗎?如果是這樣,那是預期的行爲。你可以點擊f5繼續運行,看看客戶端發生了什麼。如果清除該複選框,則可以告訴它將來不會中斷這種異常。 – 2015-05-04 16:48:14

回答

0

問題是您指定FaultContract的類型是XXXException。這是不行的,我認爲,你必須創建自己的自定義FaultContract,例如:

[DataContract] 
public class InitializationFault 
{ 
    public InitializationFault(Exception exc, string msg) 
    { 
     Exception = exc; 
     Message = msg; 
    } 

    [DataMember] 
    public Exception Exception { get; set; } 

    [DataMember] 
    public string Message { get; set; } 
} 

那麼你ServiceContract變爲:

[OperationContract] 
[FaultContract(typeof(InitializationFault))] 
//..more 
GetSysIdsResponse GetSysIds(string id); 

和您的客戶端代碼就變成了:

try 
{ 
    response = client.GetSysIds("sgentil"); 
} 
catch (FaultException<InitializationFault> e) 
{ 
    Console.WriteLine("FaultException<InitializationFault>: " + e.Detail); 
    //more 
} 
+0

可以肯定嗎? Juval Lowy用它來做。NET DivideByZeroException – 2013-05-02 15:09:48

+0

嘗試了你的方法。看到我上面編輯 – 2013-05-02 15:47:48

+0

嗯,這很奇怪。我剛剛嘗試了一個小項目來測試它,並在這裏工作。我可以調用拋出'FaultException'的方法,並且連續調用另一個。你有很多自定義配置嗎? – RoelF 2013-05-03 07:56:08

0

在我的情況下,如果接口沒有標記以下屬性,則響應爲空:

[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults = true)] 
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(Fault))] 

您可以用這些屬性標記您的操作,以使響應顯示故障詳情。