Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deserialize a WCF soap response message from a file with DataContractSerializer?

When I call a web service operation, WCF deserializes the message to the proxy class with the DataContractSerializer: why couldn't I do the same ?

Here is the soap message in the file ActLoginResponse.xml:

<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:PlotiIntf" xmlns:ns2="urn:PlotiIntf-IPloti" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"/>
    <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
        <ns2:ActLoginResponse>
            <return>
                <ResultCode>0</ResultCode>
                <ResultMessage>Login et password correct.</ResultMessage>
                <Acteur>
                    <Id>IMT_706</Id>
                    <Nom>IMA PROTECT</Nom>
                    <Prenom/>
                    <nbFI>0</nbFI>
                    <FonctionActeur>TS</FonctionActeur>
                    <Timeout>30</Timeout>
                </Acteur>
                <ZneGeoList xsi:nil="true"/>
            </return>
        </ns2:ActLoginResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The WCF proxy code for the corresponding ActLoginResponse class is :

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
[System.ServiceModel.MessageContractAttribute(WrapperName="ActLoginResponse", WrapperNamespace="urn:PlotiIntf-IPloti", IsWrapped=true)]
public partial class ActLoginResponse {

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)]
    public Ploti.PlotiClient.LoginResponseType @return;

    public ActLoginResponse() {
    }

    public ActLoginResponse(Ploti.PlotiClient.LoginResponseType @return) {
        this.@return = @return;
    }
}

So I need to parse the XML to an object instance of type ActLoginResponse.

Here is how I perform the parsing:

        ActLoginResponse body;
        FileStream stream = new FileStream("Requests\\ActLoginResponse.xml", FileMode.Open);
        XmlReader xmlReader = XmlReader.Create(stream);

        xmlReader.MoveToContent();
        xmlReader.ReadStartElement();
        xmlReader.MoveToContent();
        xmlReader.ReadStartElement();
        xmlReader.MoveToContent();
        xmlReader.ReadStartElement();
        xmlReader.MoveToContent();

        // the the reader is on the element ActLoginResponse (that is confirmed by a Log.Debug( xmlReader.ReadOuterXml());

        // I create The DataContractSerializer: exception if nampespace is not specified
        DataContractSerializer dataContract = new `DataContractSerializer`(typeof(ActLoginResponse), "ActLoginResponse", "urn:PlotiIntf-IPloti");

        ActLoginResponse actLogin = dataContract.ReadObject(xmlReader, true);

The actLogin object is created, but the content actLogin.return is allways NULL ! Did I miss something ?

like image 805
Anthony Brenelière Avatar asked May 02 '17 15:05

Anthony Brenelière


1 Answers

This is an old one, but it came up as my first search on Google for how to deserialize an object, so I thought it would be worthwhile to post the solution that worked for me in .NET Core.

In our case, we generated the code from the WSDL using the svcutil tool, and then used XmlSerializer, but it was throwing an invalid operation exception. The fix was to add the XmlRoot attribute to our object (that is, the first element of the Soap Envelope).

So we had to decorate the object like this:

    [System.Xml.Serialization.XmlRoot(ElementName = "Foo", Namespace = "ns")]
    public partial class FooType
    {
    }

And then we could deserialize like so:

            using var stream = new MemoryStream(Encoding.UTF8.GetBytes(/* stream object */));
            using var message = Message.CreateMessage(XmlReader.Create(stream), int.MaxValue, MessageVersion.Soap11);
            using var xmlStream = message.GetReaderAtBodyContents();

            var serializer = new XmlSerializer(typeof(FooType));
            var obj = serializer.Deserialize(xmlStream);

Hopefully this helps others :)

like image 111
syazdani Avatar answered Sep 22 '22 07:09

syazdani