Consuming non-wcf SOAP fault from WCF client (soap fault defined)

痴心易碎 提交于 2019-12-07 05:06:15

问题


I have a non-wcf server that I call from WCF client and I need to gain access to registered soap fault in case server throws it (it contains a feedback I need for user). I used the example from How to access SOAP 1.1 fault detail from WCF client (no fault contract) but its a pain given I DO have the fault contract defined in the wsdl, at least per SOAP specification and the fault contains error code and error string.

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

The service import recognizes all this properly and generates proper code constructs:

[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);
...

When I call the login() with invalid account I DO get proper response as per 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)
    ...

The FaultExcpetion does fire, however its blank (Message = "") and I do not see any property exposing BtsSoapException instance. Like it hasn't been deserialized at all (even though wcf knows everything it needs to do it). What am I doing wrong? How do I make WCF give me FaultException<BtsSoapException>?


回答1:


Have your tried doing something like the code shown below, you need to catch the specific soap fault contract that has the information you are looking for. The information in this MSDN article should help.

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



回答2:


I think Sixto Saez is right. You can see the BtsSoapException instance inside of the FaultException.

Definition:

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

Response:

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

if you do

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

you must see "java.lang.Exception: No user profile defined in the database for fakeuser" in the output window when you are debugging.



来源:https://stackoverflow.com/questions/8397844/consuming-non-wcf-soap-fault-from-wcf-client-soap-fault-defined

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!