【问题标题】:Consuming non-wcf SOAP fault from WCF client (soap fault defined)从 WCF 客户端使用非 wcf SOAP 错误(定义了肥皂错误)
【发布时间】:2012-01-13 22:23:32
【问题描述】:

我有一个从 WCF 客户端调用的非 wcf 服务器,如果服务器抛出它,我需要访问已注册的 soap 错误(它包含我需要用户的反馈)。我使用了来自How to access SOAP 1.1 fault detail from WCF client (no fault contract) 的示例,但考虑到我确实在 wsdl 中定义了错误协定,至少按照 SOAP 规范,并且错误包含错误代码和错误字符串,这很痛苦。

<wsdl:types>
    <schema elementFormDefault="qualified" targetNamespace="http://www.cisco.com/BTS10200/i01" xmlns="http://www.w3.org/2001/XMLSchema">
        ...
        <complexType name="BtsSoapException">
            <sequence>
                <element name="error_code" type="xsd:int"/>
                <element name="error_string" nillable="true" type="xsd:string"/>
            </sequence>
        </complexType>
        <element name="fault" type="impl:BtsSoapException"/>
...

<wsdl:message name="BtsSoapException">
    <wsdl:part element="impl:fault" name="fault"/>
</wsdl:message>
...

<wsdl:portType name="Bts10200Operations">
    <wsdl:operation name="login">
        <wsdl:input message="impl:loginRequest" name="loginRequest"/>
        <wsdl:output message="impl:loginResponse" name="loginResponse"/>
        <wsdl:fault message="impl:BtsSoapException" name="BtsSoapException"/>
    </wsdl:operation>
...

服务导入正确识别所有这些并生成正确的代码结构:

[System.Runtime.Serialization.DataContractAttribute(Name="BtsSoapException", Namespace="http://www.cisco.com/BTS10200/i01")]
[System.SerializableAttribute()]
public partial class BtsSoapException : object ...

....

[System.ServiceModel.ServiceContractAttribute(Namespace="http://www.cisco.com/BTS10200/i01", ConfigurationName="CiscoBTSService.Bts10200Operations")]
public interface Bts10200Operations {
    [System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="*")]
    [System.ServiceModel.FaultContractAttribute(typeof(TestCiscoBTS.CiscoBTSService.BtsSoapException), Action="", Name="fault")]
    TestCiscoBTS.CiscoBTSService.loginResponse login(TestCiscoBTS.CiscoBTSService.loginRequest request);
...

当我使用无效帐户调用 login() 时,我确实会根据 wsdl 得到正确的响应:

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <soapenv:Fault>
            <faultcode>soapenv:Server.generalException</faultcode>
            <faultstring></faultstring>
            <detail>
                <ns1:fault xmlns:ns1="http://www.cisco.com/BTS10200/i01">
                    <error_code>401</error_code>
                    <error_string xsi:type="xsd:string">java.lang.Exception: No user profile defined in the database for fakeuser</error_string>
                </ns1:fault>
                <ns2:exceptionName xmlns:ns2="http://xml.apache.org/axis/">com.sswitch.oam.soap.intf.BtsSoapException</ns2:exceptionName>
                <ns3:stackTrace xmlns:ns3="http://xml.apache.org/axis/">
    at com.sswitch.oam.soap.impl.UserAuth.validateUser(UserAuth.java:63)
    ...

FaultExcpetion 确实会触发,但是它的空白 (Message = "") 并且我没有看到任何暴露 BtsSoapException 实例的属性。就像它根本没有被反序列化一样(即使 wcf 知道它需要做的一切)。我究竟做错了什么?如何让 WCF 给我FaultException&lt;BtsSoapException&gt;

【问题讨论】:

  • 服务合同中的操作是否显示了 FaultContract 属性?
  • 对不起,它在那里。错过了。

标签: c# wcf soap wcf-client


【解决方案1】:

我认为 Sixto Saez 是对的。您可以在 FaultException 中看到 BtsSoapException 实例。

定义:

<complexType name="BtsSoapException">
    <sequence>
        <element name="error_code" type="xsd:int"/>
        <element name="error_string" nillable="true" type="xsd:string"/>
    </sequence>
</complexType>

回复:

<detail>
    <ns1:fault xmlns:ns1="http://www.cisco.com/BTS10200/i01">
        <error_code>401</error_code>
        <error_string xsi:type="xsd:string">java.lang.Exception: No user profile defined in the database for fakeuser</error_string>

如果你这样做了

catch (FaultException<BtsSoapException> bse)
{
    console.write(bse.Detail.error_string)
}

您在调试时必须在输出窗口中看到“java.lang.Exception: No user profile defined in the database for fakeuser”。

【讨论】:

  • 不,相信我,这是我做的第一件事。我什至检查了异常类型以确保它是纯的FaultException,而不是继承的FaultException&lt;T&gt;。出于理智考虑,我什至创建了一个像 Sixto Saez 发布的那样的级联捕获,它跳过通用版本并停止在非通用父级上。如果就这么简单,我就不会在上面发布赏金了:)
  • 呜呜!!奇怪的事情。尝试将命名空间属性添加到 FaultContractAttribute。 [System.ServiceModel.FaultContractAttribute(typeof(TestCiscoBTS.CiscoBTSService.BtsSoapException), Action="", Name="fault", Namespace="cisco.com/BTS10200/i01")]
  • Arg!! StackOverflow 引擎解析 cmets 中的命名空间 URI。嗯,我想你会明白的......
  • 嗯,它在DataContract 中为BtsSoapException 定义了命名空间。不过,我尝试了您的建议,但没有帮助。我不认为它是服务发现的问题,我现在认为它是 WCF 中的一个错误。
  • 我开始也是这么想的,但是很多错误都有我建议的愚蠢的解决方案。
【解决方案2】:

您是否尝试过执行如下所示的代码,您需要捕获包含您要查找的信息的特定肥皂故障合约。 this MSDN article 中的信息应该会有所帮助。

var proxy = new WhatEverYourServiceProxyClassIsNamed();
try
{
    //your call logic here

    proxy.Close();
}
catch (FaultException<BtsSoapException> bse)
{
    //Get the info you're looking for in the strongly typed soap fault:

    proxy.Abort();
}
catch (FaultException fe)
{
    //Do something appropriate for a non-typed soap fault

    proxy.Abort();
}
finally
{
    if ((ICommunicationObject)proxy).State != CommunicationState.Closed)
        proxy.Abort();
}

【讨论】:

  • 问题不是我发现的,问题是WCF没有抛出FaultException&lt;BtsSoapException&gt;,即使指定了错误契约,它只会抛出FaultException
  • 那么问题是 WCF 对肥皂故障的反序列化和您的 Add Reference/SvcUtil 进程生成的 TestCiscoBTS.CiscoBTSService.BtsSoapException 类的定义中的“断开连接”。要解决此问题,请尝试使用强类型故障协定创建简单的 WCF 服务,并确保您可以在服务代码中触发该故障。调用服务,生成故障并验证客户端是否可以捕获该特定故障。最后,将soap XML 中的故障与此问题中的故障XML 进行比较。 (续)
  • (续)您可能必须修改生成的代理故障合同以匹配发送的序列化 XML 但您的 java 服务。您还应该查看此MSDN article,因为 WCF 如何支持肥皂错误定义存在一些限制(请参阅文章的最后一部分)。
  • 据我所见,我看到的唯一不同寻常的是存在与 Java 相关的 exceptionName 和 stackTrace,但这些细节部分位于不同的命名空间 (http://xml.apache.org/axis/)。这可能是 WCF 中的一个错误,除非详细架构针对故障响应是 1-1,否则解析器会失败?我一定会尝试创建一个在 BtsException 中出错的 wcf 服务,看看会发生什么......
  • 嗯,输出与我从服务中得到的匹配,没有 java 细节。所以我在这一点上的结论是,如果故障包含的信息多于 WSDL 定义的信息,则 WCF 无法反序列化故障。我认为这归类为错误,因为 XML 规范规定您应该忽略其他名称空间中的多余 XML 片段,我将在 connect 上发布此内容。至于这个话题,由于赏金超时是半小时,而且我认为没有可行的解决方案,我会接受你的回答,并赏金指出我的诊断过程。为来之不易的积分浪费而感到羞耻。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-22
  • 1970-01-01
相关资源
最近更新 更多