3

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.

Roland
  • 43
  • 1
  • 3
  • Does [how to ignore soap stuff on deserializing xml to object?](https://stackoverflow.com/q/20478234/3744182) help? – dbc Oct 21 '19 at 16:51
  • What happens if you take the code generated by adding the service reference in .Net Framework and copy it into your .Net Core app, build, and run. Does it work then? – dbc Oct 21 '19 at 17:09
  • I tried adding the code generated by .Net Framework but that led to the same issue. Seems I'm left only with the solution of deserializing it by removing the soap stuff – Roland Oct 23 '19 at 12:42

0 Answers0