我在使用.NET 4.5 WCF客户端获取UPS RateWS服务时遇到soap 1.1 fault detail元素时出现问题。
问题在于,虽然faultcode和faultstring元素在异常时恢复为.Code
和.Message
属性。详细对象未正确反序列化,并且始终为空数组。
我通过从UPS Rating developer kit Rates_Pkg_Gnd.zip文件SCHEMA-WSDLs目录中解压缩wsdl和xsds并在我的文件上指向RateWS.wsdl上的Visual Studio 2013s添加服务引用对话框来生成WCF客户端系统
实际的线肥故障信息如下所示:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header />
<soapenv:Body>
<soapenv:Fault>
<faultcode>Client</faultcode>
<faultstring>An exception has been raised as a result of client data.</faultstring>
<detail>
<err:Errors xmlns:err="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1">
<err:ErrorDetail>
<err:Severity>Hard</err:Severity>
<err:PrimaryErrorCode>
<err:Code>111285</err:Code>
<err:Description>The postal code 21740 is invalid for AB Canada.</err:Description>
</err:PrimaryErrorCode>
</err:ErrorDetail>
</err:Errors>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
我尝试捕获System.ServiceModel.FaultException<UPS.RateService.ErrorDetailType[]>
,但Detail属性始终是UPS.RateService.ErrorDetailType [0]的数组 - 零大小。
类似地,捕获FaultException
并调用.CreateMessageFault()
来访问.GetDetail<XmlElement>()
会产生一个包含ArrayOfErrorDetailType元素的XML对象,其中没有任何内容。使用.GetReaderAtDetailContents()
获取XmlReader的替代方法会产生相同的虚假结构。
这是错误消息xsd:
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:error="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1" elementFormDefault="qualified" targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="Errors">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="unbounded" name="ErrorDetail" type="error:ErrorDetailType" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="ErrorDetailType">
<xsd:sequence>
<xsd:element name="Severity" type="xsd:string" />
<xsd:element name="PrimaryErrorCode" type="error:CodeType" />
<xsd:element minOccurs="0" name="MinimumRetrySeconds" type="xsd:string" />
<xsd:element minOccurs="0" name="Location" type="error:LocationType" />
<xsd:element minOccurs="0" maxOccurs="unbounded" name="SubErrorCode" type="error:CodeType" />
<xsd:element minOccurs="0" maxOccurs="unbounded" name="AdditionalInformation" type="error:AdditionalInfoType" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CodeType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" />
<xsd:element name="Description" type="xsd:string" />
<xsd:element minOccurs="0" name="Digest" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AdditionalInfoType">
<xsd:sequence>
<xsd:element name="Type" type="xsd:string" />
<xsd:element maxOccurs="unbounded" name="Value" type="error:AdditionalCodeDescType" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AdditionalCodeDescType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" />
<xsd:element minOccurs="0" name="Description" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LocationType">
<xsd:sequence>
<xsd:element minOccurs="0" name="LocationElementName" type="xsd:string" />
<xsd:element minOccurs="0" name="XPathOfElement" type="xsd:string" />
<xsd:element minOccurs="0" name="OriginalValue" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
答案 0 :(得分:3)
为了实现这一点,我在序列中添加了一个虚拟元素:
<xsd:element name="Errors">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ErrorDetail" type="error:ErrorDetailType" maxOccurs="unbounded"/>
<xsd:element name="TestElement" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
由于某种原因,允许WCF正确序列化故障。这会强制WCF生成在故障合同中传递的新类“错误”。然后,您可以捕获FaultException<Errors>
例外并访问ErrorDetailType[]
。
答案 1 :(得分:2)
我意识到这是一个古老的问题,但我在另一个问题上找到了解决方案 - FaultException.Detail coming back empty
将生成的类从ErrorDetailType重命名为ErrorDetail意味着我可以迭代错误。
答案 2 :(得分:0)
最终我找到的解决方案是修改WSDL,以便不定义<detail />
元素的内容,并使用svcutil
生成代理类。当我这样做时,我可以访问原始的<err:Errors />
XML元素:
var fault = ex.CreateMessageFault();
var faultXml = fault.GetDetail<XmlElement>();
这允许我使用XPath来获取err:Description元素的内容。使用原始的WSDL,我什么也得不到。