C# 如何处理 WCF 故障异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/17097839/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Handle WCF Fault Exception
提问by The Unique Paul Smith
I am trying to add more information regarding a SOAP fault in a open source client application. The client is setup to call "HandleFault" whenever it encounters any SOAP fault. The Handle Fault method is shown below:
我正在尝试在开源客户端应用程序中添加有关 SOAP 错误的更多信息。客户端设置为在遇到任何 SOAP 错误时调用“HandleFault”。处理故障方法如下所示:
   public static void HandleFault(Message message) {
        MessageFault fault = MessageFault.CreateFault(message, Int32.MaxValue);
        throw System.ServiceModel.FaultException.CreateFault(fault,
            typeof(PermissionDeniedFault),
            typeof(EndpointUnavailable),
            typeof(InvalidRepresentation),
            typeof(UnwillingToPerformFault),
            typeof(CannotProcessFilter),
            typeof(AnonymousInteractionRequiredFault)
        );
    }
Here is a portion of the SOAP Fault that is passed in as "message" when I try and do something like change a phone number to invalid format from the client.
这是 SOAP Fault 的一部分,当我尝试从客户端将电话号码更改为无效格式时,它作为“消息”传入。
  <s:Body u:Id="_2">
<Fault xmlns="http://www.w3.org/2003/05/soap-envelope">
  <Code>
    <Value>Sender</Value>
    <Subcode>
      <Value xmlns:a="http://schemas.xmlsoap.org/ws/2004/09/transfer">a:InvalidRepresentation</Value>
    </Subcode>
  </Code>
  <Reason>
    <Text xml:lang="en-US">The request message contains errors that prevent processing the request.</Text>
  </Reason>
  <Detail>
    <RepresentationFailures xmlns="http://schemas.microsoft.com/2006/11/ResourceManagement" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <AttributeRepresentationFailure>
        <AttributeType>OfficePhone</AttributeType>
        <AttributeValue>(123)456-7890</AttributeValue>
        <AttributeFailureCode>ValueViolatesRegularExpression</AttributeFailureCode>
        <AdditionalTextDetails>The specified attribute value does not satisfy the regular expression.</AdditionalTextDetails>
      </AttributeRepresentationFailure>
      <CorrelationId>11042dda-3ce9-4563-b59e-d1c1355819a4</CorrelationId>
    </RepresentationFailures>
  </Detail>
</Fault>
Whenever that Fault is encountered, the client only returns back "The request message contains errors that prevent processing the request.", I would like to include the "AttributeRepresentationFailure" node and child nodes before re-throwing the exception in the client.
每当遇到该错误时,客户端只会返回“请求消息包含阻止处理请求的错误。”,我想在客户端重新抛出异常之前包含“ AttributeRepresentationFailure”节点和子节点。
The way I understand it is that I need to define a Fault class that contains those details to be deseralized, so that the call to "CreateFault" can return a . I've read through http://msdn.microsoft.com/en-us/library/ms733841.aspxbut I just don't understand exactly how to define the class so that the client knows what type of fault is thrown.
我的理解是,我需要定义一个包含要反序列化的详细信息的 Fault 类,以便对“CreateFault”的调用可以返回一个 . 我已经通读了http://msdn.microsoft.com/en-us/library/ms733841.aspx,但我只是不明白如何定义类以便客户端知道抛出什么类型的错误。
UPDATE
更新
In the client side handle fault method I added
在客户端处理故障方法中我添加了
 try
        {
            throw faultexcept;
        }
        catch (System.ServiceModel.FaultException<InvalidRepresentation> invalidRepresentationFault)
        {
            throw invalidRepresentationFault;
        }
        catch (System.ServiceModel.FaultException otherFault)
        {
            throw otherFault;
        }
        catch (Exception ex)
        {
            throw ex;
        }
The fault is always caught under the base fault class "otherFault". My InvalidRepresentation class is defined as below
故障总是在基本故障类“otherFault”下捕获。我的 InvalidRepresentation 类定义如下
 [DataContract(Namespace = Constants.Rm.Namespace)]
public class InvalidRepresentation 
{
    private string _attributeType;
    private string _attributeValue;
    private string _attributeFailureCode;
    private string _additionalTextDetails;
    [DataMember]
    public string AttributeType
    {
        get { return _attributeType; }
        set { _attributeType = value; }
    }
    [DataMember]
    public string AttributeValue
    {
        get { return _attributeValue; }
        set { _attributeValue = value; }
    }
    [DataMember]
    public string AttributeFailureCode
    {
        get { return _attributeFailureCode; }
        set { _attributeFailureCode = value; }
    }
    [DataMember]
    public string AdditionalTextDetails
    {
        get { return _additionalTextDetails; }
        set { _additionalTextDetails = value; }
    }
    public InvalidRepresentation() {
    }
}
回答by Fredrik
I'm using the math example from the article you referred to. Create the fault class:
我正在使用您提到的文章中的数学示例。创建故障类:
[DataContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public class MathFault
{    
...
}
Decorate your method with OperationContract, e.g.
用 OperationContract 装饰你的方法,例如
[OperationContract]
[FaultContract(typeof(MathFault))]
int Divide(int n1, int n2);
Create your MathFault object with sensible data. Wrap it and throw it:
使用合理的数据创建您的 MathFault 对象。把它包起来扔掉:
throw new FaultException<MathFault>(yourFault);
Hope this helps.
希望这可以帮助。
回答by Jason
To add to Fredrik's answer, your Fault class can be whatever you need to convey the details of your custom error to the client. It doesn't have to inherit from another class or implement an interface. It just needs to be marked with the DataContract attribute.
要添加 Fredrik 的答案,您的 Fault 类可以是您需要将自定义错误的详细信息传达给客户端的任何内容。它不必从另一个类继承或实现接口。它只需要使用 DataContract 属性进行标记。
As for catching it on the client side:
至于在客户端捕获它:
try
{
    ...
}
catch (FaultException<MathFault> mathFault)
{
    // handle a math fault
}
catch (FaultException<OtherCustomFault> otherFault)
{
    // handle another type of custom fault
}
catch (Exception ex)
{
    // regular exception handling
}
回答by The Unique Paul Smith
I was finally able to find a resolution to this, thanks to everyone who helped! This isn't the best solution and needs to be cleaned up, but it works while until I learn more about WCF and SOAP Faults. Also, I don't have access to the service code, just the client code. The client code is being ran as a powershell module.
我终于能够找到解决方案,感谢所有帮助过的人!这不是最好的解决方案,需要清理,但它可以工作,直到我了解更多关于 WCF 和 SOAP 错误。另外,我无权访问服务代码,只能访问客户端代码。客户端代码作为 powershell 模块运行。
InvalidRepresentationFault Class
InvalidRepresentationFault 类
using System.Runtime.Serialization;
namespace Client.Faults {
    public class InvalidRepresentationFault 
    {
        public InvalidRepresentationFault() {}
    }
    [DataContract(Namespace = Constants.Rm.Namespace)]
    public class RepresentationFailures
    {
        [DataMember()]
        public FailureDetail AttributeRepresentationFailure;
    [DataContract(Namespace = Constants.Rm.Namespace)]
    public class FailureDetail
    {
        [DataMember(Order = 1)]
        public string AttributeType;
        [DataMember(Order = 2)]
        public string AttributeValue;
        [DataMember(Order = 3)]
        public string AttributeFailureCode;
        [DataMember(Order = 4)]
        public string AdditionalTextDetails;
    }
    [DataMember]
    public string CorrelationId;
}
}
}
Client HandleFault Code
客户端处理错误代码
 public static void HandleFault(Message message) {
        MessageFault fault = MessageFault.CreateFault(message, Int32.MaxValue);
        //Let the fault exception choose the best fault to handle?
        System.ServiceModel.FaultException faultexcept = System.ServiceModel.FaultException.CreateFault(fault,
            typeof(PermissionDeniedFault),
            typeof(AuthenticationRequiredFault),
            typeof(AuthorizationRequiredFault),
            typeof(EndpointUnavailable),
            typeof(FragmentDialectNotSupported),
            typeof(InvalidRepresentationFault),
            typeof(UnwillingToPerformFault),
            typeof(CannotProcessFilter),
            typeof(FilterDialectRequestedUnavailable),
            typeof(UnsupportedExpiration),
            typeof(AnonymousInteractionRequiredFault),
            typeof(RepresentationFailures)
        );
        try
        {
            throw faultexcept;
        }
        catch (System.ServiceModel.FaultException<RepresentationFailures> invalidRepresentationFault)
        {
            throw new Exception(
                String.Format(
                    "{0}\r\nfor Attribute \"{1}\" with Value \"{2}\"",
                        invalidRepresentationFault.Detail.AttributeRepresentationFailure.AdditionalTextDetails,
                        invalidRepresentationFault.Detail.AttributeRepresentationFailure.AttributeType,
                        invalidRepresentationFault.Detail.AttributeRepresentationFailure.AttributeValue
                    ),
                 invalidRepresentationFault
             );
        }
        catch (System.ServiceModel.FaultException otherFault)
        {
            throw otherFault;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
Now when the service throws a SOAP Fault it gets deserialized into the "RepresentationFailures" class, which I can customize before re-throwing back upstream (in this case to powershell)
现在,当服务抛出 SOAP 错误时,它会反序列化为“RepresentationFailures”类,我可以在重新返回上游之前对其进行自定义(在本例中为 powershell)

