0
votes

We are trying to implement a WCF proxy/client for a PHP SOAP service. We retrieved the WSDL and created a service reference in a command line application. We are able to retrieve the result of a SOAP operation, but it turns out that returned lists always end up as null, when tapping the wire with fiddler or test it in SoapUI we can clearly see data being returned.

I've followed a few advices in similar issue posts and came up with a minimalistic deserialization example that seems to have the same issue.

Message m = Message.CreateMessage(XmlReader.Create("response.xml"), int.MaxValue, MessageVersion.Soap11);
SoapReflectionImporter importer = new SoapReflectionImporter(new SoapAttributeOverrides(), "http://brokenns");
XmlTypeMapping mapping = importer.ImportTypeMapping(typeof(getDeviceListResponse));
XmlSerializer serializer = new XmlSerializer(mapping);
getDeviceListResponse response = (getDeviceListResponse)serializer.Deserialize(m.GetReaderAtBodyContents());
Console.WriteLine([email protected] == null  ? "List is null" : "List is not null");
< List is null

service.wsdl

<?xml version="1.0" encoding="utf-8"?>
<definitions 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://brokenns" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"
  targetNamespace="http://brokenns">
  <types>
    <xsd:schema targetNamespace="http://brokenns">
      <xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
      <xsd:import namespace="http://schemas.xmlsoap.org/wsdl/" />
      <xsd:complexType name="Device">
        <xsd:sequence>
          <xsd:element name="id" type="xsd:int" minOccurs="1" maxOccurs="1" />
        </xsd:sequence>
      </xsd:complexType>
      <xsd:complexType name="DeviceListResult">
        <xsd:sequence>
          <xsd:element name="message" type="xsd:string" minOccurs="0" maxOccurs="1" />
          <xsd:element name="deviceList" type="tns:Device" minOccurs="0" maxOccurs="unbounded" />
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>
  </types>
  <message name="getDeviceListRequest">
    <part name="loadSimCard" type="xsd:boolean" />
  </message>
  <message name="getDeviceListResponse">
    <part name="return" type="tns:DeviceListResult" />
  </message>
  <portType name="DevicesServicePortType">
    <operation name="getDeviceList">
      <documentation>Returns device list</documentation>
      <input message="tns:getDeviceListRequest" />
      <output message="tns:getDeviceListResponse" />
    </operation>
  </portType>
  <binding name="DevicesServiceBinding" type="tns:DevicesServicePortType">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
    <operation name="getDeviceList">
      <soap:operation soapAction="https://myservice.com/ws/devices.php/getDeviceList" style="rpc" />
      <input>
      <soap:body use="literal" namespace="http://brokenns" /></input>
      <output>
        <soap:body use="literal" namespace="http://brokenns" /></output>
    </operation>
  </binding>
  <service name="DevicesService">
    <port name="DevicesServicePort" binding="tns:DevicesServiceBinding">
      <soap:address location="https://myservice.com/ws/devices.php" />
    </port>
  </service>
</definitions>

response.xml

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope 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/">
    <SOAP-ENV:Body>
        <ns1:getDeviceListResponse xmlns:ns1="http://brokenns">
            <return>
                <message>works</message>
                <deviceList>
                    <id>48</id>
                </deviceList>
                <deviceList>
                    <id>41</id>
                </deviceList>
                <deviceList>
                    <id>42</id>
                </deviceList>
            </return>
        </ns1:getDeviceListResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Can anybody spot the error in the service wsdl that would render my list null after deserialisation?

I've tried doing a simple back and forth serialisation with the generated contracts and couldn't spot an issue there, makes me believe it has something to do with the namespaces, omitting them didn't help though.

<?xml version="1.0" encoding="utf-16"?>
<getDeviceListResponse xmlns:ns1="http://brokenns">
  <return>
    <message>sd</message>
    <deviceList>
      <id>2323</id>
    </deviceList>
    <deviceList>
      <id>67</id>
    </deviceList>
  </return>
</getDeviceListResponse>
1
The reason may be that WCF serializes the universal list into an array to send over the network. The configuration just tells svcutil to create a proxy and convert them back to a common list for convenience. You can try to modify the collection type when you created a service reference. For more information about it, you can refer to this link: stackoverflow.com/questions/63702018/… - Ding Peng
None of the collection type change the fact that the list is null after deserialisation within the wcf proxy. - Sven Mawby
Do you want to call PHP SOAP Service in .net? If you want to call PHP SOAP Service in .net you can refer to this link: forums.asp.net/t/… - Ding Peng
The service is indeed using NuSoap on the other end, but the link has no answer for me. - Sven Mawby

1 Answers

-1
votes

The following works with serialization :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XmlReader reader = XmlReader.Create(FILENAME);
            XmlSerializer serializer = new XmlSerializer(typeof(Envelope));
            Envelope envelope = (Envelope)serializer.Deserialize(reader);

        }
    }
    [XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    public class Envelope
    {
        [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
        public Body Body { get; set; }
    }
    public class Body
    {
        [XmlElement(ElementName = "getDeviceListResponse", Namespace = "http://brokenns")]
        public getDeviceListResponse getDeviceListResponse { get; set; }
    }
    public class getDeviceListResponse
    {
        [XmlElement(ElementName = "return", Namespace = "")]
        public Return Return { get; set; }
    }
    public class Return
    {
        public string message { get; set; }
        [XmlElement()]
        public List<deviceList> deviceList { get; set; }
    }
    public class deviceList
    {
        public int id { get; set; }
    }
}