0

I have a soap result in this format

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
       <soap:Body>
          <sendSmsResponse xmlns="https://srvc.blablabla.com/SmsProxy">
            <sendSmsResult>
               <ErrorCode>0</ErrorCode>
               <PacketId>90279163</PacketId>
               <MessageIdList>
                  <MessageId>4402101870</MessageId>
                  <MessageId>4402101871</MessageId>
               </MessageIdList>
            </sendSmsResult>
          </sendSmsResponse>
      </soap:Body>
  </soap:Envelope>

I want to convert it to an object in order to use it in my Windows service.

Here is the code for doing that:

    public static T DeserializeInnerSoapObject<T>(string soapResponse)
    {
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.LoadXml(soapResponse);

        var soapBody = xmlDocument.GetElementsByTagName("sendSmsResponse")[0];
        string innerObject = soapBody.InnerXml;

        XmlSerializer deserializer = new XmlSerializer(typeof(T));
        
        using (StringReader reader = new StringReader(innerObject))
        {
            return (T)deserializer.Deserialize(reader);
        }
    }

And here are the classes I created for the process:

[XmlRoot(ElementName = "sendSmsResult", Namespace ="https://srvc.blablabla.com/SmsProxy")]
public class sendSmsResult
{
    public string ErrorCode { get; set; }
    public string PacketId { get; set; }
    public MessageId[] MessageIdList{ get; set; }
}

public class MessageId
{
    [XmlElement(ElementName = "MessageId", Namespace = "https://srvc.blablabla.com/SmsProxy")]
    public string messageId { get; set; }
}

In the service, I call the above method as

var result = DeserializeInnerSoapObject<sendSmsResult>(test);

The result returns correct values for ErrorCode and PacketId and the correct number of MessageIds for MessageIdArray, but the MessageIds are null.

Am I doing something wrong with MessageIdArray?

Any help appreciated.

ADyson
  • 57,178
  • 14
  • 51
  • 63
ilhank
  • 148
  • 6
  • 25
  • 2
    Don't you have an auto-generated service/client stub? Are you using WCF or a 3rd party Soap Service? – Fildor Nov 27 '20 at 09:01
  • Also see: https://stackoverflow.com/a/4304356/982149 and maybe better: https://stackoverflow.com/a/14360303/982149 – Fildor Nov 27 '20 at 09:03
  • an HttpWebRequest result comes in XML format that's why I have string consists of XML content. – ilhank Nov 27 '20 at 09:06
  • @Fildor thank you very much for your help and time I don't have documentation for web service calls, therefore, I tried to convert the XML string to the object I created. I mostly did it but as I stated in my object MessageId's come null after converting to object. – ilhank Nov 27 '20 at 09:14
  • 3
    How are you expecting that `MessageIdArray` in the C# will map to `MessageIdList` in the XML? You either need to give the C# variable the same name, or set an attribute to tell XmlSerializer which XML element to use for this property. – ADyson Nov 27 '20 at 09:18
  • @ilhank, SOAP uses XML, but there's no need to deal with XML when using SOAP. Just add connected service (formerly service reference) to your project and you'll get auto-generated client and data contract classes. The rest will be done inside service client package. – Dennis Nov 27 '20 at 09:18
  • 3
    Anyway you don't necessarily need documentation for the service. As long as it publishes a WSDL (which a SOAP service ought to), you can get visual studio to auto-generate the C# classes you need. That was Fildor's point (and Dennis's). – ADyson Nov 27 '20 at 09:20
  • @ADyson thank you very much, in my code I actually have MessageIdList instead of MessageIdArray. While writing it here I changed it. – ilhank Nov 27 '20 at 09:25
  • 1
    ^^ What ADyson says. BTW, nowadays I'd expect from a decent SOAP-Servive provider to have ready-to-use client libs for at least the most used platforms and languages. :/ if not a protobuf / gRPC alternative. – Fildor Nov 27 '20 at 09:29
  • @ilhank that's a good reason for using copy and paste :-) – ADyson Nov 27 '20 at 09:34

1 Answers1

2

What I like to do when I encounter a problem like this is reverse the process. So create an SendSmsResult object and fill the attributes. Then serialize the object to view the generated xml. This will show you that your code will create an xml looking like this

<?xml version="1.0" encoding="utf-16"?>
<sendSmsResult xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="https://srvc.blablabla.com/SmsProxy">
  <MessageIdList>
    <MessageId>
      <MessageId>11</MessageId>
    </MessageId>
  </MessageIdList>
</sendSmsResult>

There is an MessageId element too many.

if you update the class to:

[XmlRoot(ElementName = "sendSmsResult", Namespace = "https://srvc.blablabla.com/SmsProxy")]
public class sendSmsResult
{
    public string ErrorCode { get; set; }
    public string PacketId { get; set; }

    [XmlArrayItem("MessageId", IsNullable = false)]
    public List<string> MessageIdList{get;set;}
}

It will work and your properties will be filled with correct data.

martijn
  • 485
  • 2
  • 9