8

我正在尝试在开源客户端应用程序中添加有关 SOAP 错误的更多信息。客户端设置为在遇到任何 SOAP 错误时调用“HandleFault”。Handle Fault 方法如下图所示:

   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)
        );
    }

这是 SOAP 错误的一部分,当我尝试从客户端将电话号码更改为无效格式时,它作为“消息”传入。

  <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>

每当遇到该故障时,客户端只返回“请求消息包含阻止处理请求的错误。”,我想在客户端重新抛出异常之前包含“ AttributeRepresentationFailure ”节点和子节点。

我理解它的方式是我需要定义一个包含要反序列化的详细信息的故障类,以便对“CreateFault”的调用可以返回一个 . 我已经阅读了http://msdn.microsoft.com/en-us/library/ms733841.aspx,但我只是不明白如何定义类,以便客户端知道抛出了什么类型的错误。

更新

在我添加的客户端处理故障方法中

 try
        {
            throw faultexcept;
        }
        catch (System.ServiceModel.FaultException<InvalidRepresentation> invalidRepresentationFault)
        {
            throw invalidRepresentationFault;
        }
        catch (System.ServiceModel.FaultException otherFault)
        {
            throw otherFault;
        }
        catch (Exception ex)
        {
            throw ex;
        }

故障总是在基本故障类“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() {

    }
}
4

3 回答 3

3

要添加到 Fredrik 的答案,您的 Fault 类可以是您将自定义错误的详细信息传达给客户端所需的任何内容。它不必从另一个类继承或实现接口。它只需要使用 DataContract 属性进行标记。

至于在客户端捕获它:

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
}
于 2013-06-14T01:15:06.703 回答
3

我终于能够找到解决方案,感谢所有帮助过的人!这不是最好的解决方案,需要清理,但在我了解有关 WCF 和 SOAP 错误的更多信息之前,它仍然有效。另外,我无权访问服务代码,只能访问客户端代码。客户端代码作为 powershell 模块运行。

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;
}

}

客户端处理故障代码

 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;
        }
    }

现在,当服务抛出 SOAP 错误时,它会被反序列化为“RepresentationFailures”类,我可以在重新返回上游之前对其进行自定义(在本例中为 powershell)

于 2013-06-14T17:35:38.787 回答
2

我正在使用您提到的文章中的数学示例。创建故障类:

[DataContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public class MathFault
{    
...
}

使用 OperationContract 装饰您的方法,例如

[OperationContract]
[FaultContract(typeof(MathFault))]
int Divide(int n1, int n2);

使用合理的数据创建您的 MathFault 对象。把它包起来扔掉:

throw new FaultException<MathFault>(yourFault);

希望这可以帮助。

于 2013-06-13T22:46:44.070 回答