I’m trying to write a C# .NET app that can deserialize a SOAP response from a webservice. The webservice (here called ‘Wibble’) has no WSDL (Grrrrrrr). I have a copy of a complete sample response which I believe I can use to generate intermediate classes, but despite trying a number of different methods, I can’t get a sane object from the response.
The first few lines of the response looks like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:inspectResponse xmlns:ns1="ProjectService" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<inspectReturn href="#id0"/>
</ns1:inspectResponse>
<multiRef xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="Wibble" id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:Project">
<category xsi:type="ns2:Category" xsi:nil="true"/>
<classId xsi:type="xsd:long">1000000</classId>
[...]
</multiRef>
<multiRef xmlns:ns3="Wibble" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id3" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns3:ProjectData">
<author xsi:type="ns3:User" xsi:nil="true" />
<authorUserId xsi:type="xsd:long">5289027</authorUserId>
<classId xsi:type="xsd:long">0</classId>
<comments xsi:type="xsd:string">Some comments.</comments>
[...]
</multiRef>
</soapenv:Body>
</soapenv:Envelope>
etc…
Firstly, if I try to use a SoapFormatter like this:
var formatter = new SoapFormatter();
var blah = formatter.Deserialize(memstream);
return blah.ToString();
I get a SerializationException: Parse Error, no assembly associated with Xml key ns1 inspectResponse
So I guess it’s missing a class called inspectResponse that it can map the first element onto. So I crack out xsd.exe and generate some xsds from the XML file. From here, I generate a 52KB C# class that contains a whole bunch of code that (I’m guessing) contains all the classes that the XML file can map to. I include that, and re-run the above code and get exactly the same error.
So then I get the idea that now I have the auto-generated classes, I can just use an XmlSerializer object and try and deserialize that way. I write this:
var ss = new XmlSerializer(typeof(Classes.Envelope));
object blah;
using (var xr = XmlReader.Create(new StringReader(response)))
{
ss.Deserialize(xr);
blah = ss.Deserialize(xr);
}
return blah.ToString();
This time I get a new InvalidOperationException: There is an error in XML document (2, 356). ---> System.InvalidOperationException: The specified type was not recognized: name='Project', namespace='Wibble', at <multiRef xmlns=''>.
The auto-generated code doesn’t contain a Project class, although it does contain a multiRef class. Presumably it’s barfing because no Project class exists. I try creating a placeholder:
[Serializable]
[XmlType(TypeName = "Project", Namespace = "Wibble")]
public class Project
{
}
but that has no effect.
Am I way off the mark here, or am I just missing some small thing? I appreciate it’s a fairly complex XML response with multiple multiRef elements all of different types, but I would have expected that the SoapSerializer should have been able to do something with it.
Okay, why dont you try loading the response into an XMLDomDocument and use XPATH expressions or XSLT to query the nodes that you are interested in. Then a custom mapper class could map the node attributes into your POCO classes.
Just a thought and a bad work around in case you dont find anything else, but I am surprised that a SOAP return message has no WSDL to it. Is this a public service .
Have you also tried appending ?WSDL at the end of the service URL and see what happens.