我正在尝试在开源客户端应用程序中添加有关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 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>
每当遇到Fault时,客户端只返回“请求消息包含阻止处理请求的错误。”,我想在重新包含“ AttributeRepresentationFailure ”节点和子节点之前 - 在客户端中抛出异常。
我理解它的方式是我需要定义一个Fault类,其中包含要解除序列化的细节,以便对“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() {
}
}
答案 0 :(得分: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
}
答案 1 :(得分:2)
我终于能够找到解决方案,感谢所有帮助过的人!这不是最好的解决方案,需要清理,但在我了解有关WCF和SOAP Faults的更多信息之前,它一直有效。此外,我无权访问服务代码,只访问客户端代码。客户端代码作为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 Fault时,它会被反序列化为“RepresentationFailures”类,我可以在重新向上游重新抛出之前自定义它(在本例中为powershell)
答案 2 :(得分:1)
我正在使用您提到的文章中的数学示例。创建故障类:
[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);
希望这有帮助。