Deserialize the soap xml response in a .netcore app

Viewed 3079

I have to call a soap service from a C# .net core app and get the results in a class that I can use to do some logic. I did the soap request and the remote call works fine, but now I have to deserialize the xml soap response into a class. Here's an example of the response:

<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://some_domain/soap/ApplicationServices">
  <SOAP-ENV:Body>
    <ns1:preparelabelsResponse xmlns:ns1="http://some_domain/soap/ApplicationServices">
      <return xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="tns:PrepareReturn[1]">
        <item xsi:type="tns:PrepareReturn">
          <clientref xsi:type="xsd:string">2015/0418/001</clientref>
          <pclid xsi:type="xsd:string"></pclid>
          <error xsi:type="xsd:string">Invalid timestamp 20191018105727</error>
        </item>
      </return>
    </ns1:preparelabelsResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Since I'm using Visual Studio 2017 I tried adding a connected service in my .netcore app using the WCF Web Service Reference Provider and then call the method. The call failed with the message: Wrong XML format, that was probably generated by the server. Doing the same steps in a .net framework app worked fine though, and I got the proper response. So I suspect something is different in the .netcore wcf provider. My second approach was to create the soap request manually and then parse the soap response. For constructing the request I have an elegant solution, but for parsing the response I don't. I tried to use the classes that were generated by the wcf provider, but the xml deserialization didn't work. I then tried to change the attributes to get it right, but didn't help. I added below those classes:

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "1.0.0.1")]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
[System.ServiceModel.MessageContractAttribute(WrapperName="preparelabelsResponse", WrapperNamespace="encoded", IsWrapped=true)]
public partial class preparelabelsResponse
{    
    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)]
    public PrepareReturn[] @return;

    public preparelabelsResponse()
    {
    }

    public preparelabelsResponse(PrepareReturn[] @return)
    {
        this.@return = @return;
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "1.0.0.1")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Xml.Serialization.SoapTypeAttribute(Namespace="http://some_domain/soap/ApplicationServices")]
public partial class PrepareReturn
{     
    private string clientrefField;

    private string pclidField;

    private string errorField;

    /// <remarks/>
    public string clientref
    {
        get
        {
            return this.clientrefField;
        }
        set
        {
            this.clientrefField = value;
        }
    }

    /// <remarks/>
    public string pclid
    {
        get
        {
            return this.pclidField;
        }
        set
        {
            this.pclidField = value;
        }
    }

    /// <remarks/>
    public string error
    {
        get
        {
            return this.errorField;
        }
        set
        {
            this.errorField = value;
        }
    }
}

And the xml deserialization:

var soapResponse = XDocument.Load(sr);
XNamespace myns = "http://some_domain/soap/ApplicationServices";
var xml = soapResponse.Descendants(myns + "preparelabelsResponse").FirstOrDefault().ToString();
var result = Deserialize<preparelabelsResponse>(xml);

...

public static T Deserialize<T>(string xmlStr)
{
    var serializer = new XmlSerializer(typeof(T));
    T result;
    using (TextReader reader = new StringReader(xmlStr))
    {
        result = (T)serializer.Deserialize(reader);
    }
    return result;
}

So what I could do is to strip the xml away of all the namespaces and attributes and deserialize it to a simple class, but that is not an elegant solution for my problem. What I want is to be able to create/decorate my classes in such a way that the deserialization will work without any altering of the actual xml contents.

0 Answers
Related