2013-05-02 156 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))] 

您可以用这些属性标记您的操作,以使响应显示故障详情。