Software development isn’t always the glamorous profession it might seem to be .. Many times you have to use yesterdays technology at work, even when you know there is a newer and shinier piece of kit you could have used. Some people even get stuck using the day-before-yesterday’s tech, but that is another story completely. Newer pieces of software usually have more capabilities, and is much more pleasurable to work with than yesterday’s. It’s a wonder that IT-workers ten years ago survived having only crude and primitive tools at their disposal. Just kidding! 😛 Anyhow, to the point at hand:
I had to make a client for a set of SOAP services. Call it “web services” if you like, although it seems to me that term has gone out of fashion. The things is that the services are written in Java, don’t know which version, and the client had to be written in .Net 2.0. After a little searching I figured out I should use the “wsdl.exe” tool supplied with the Microsoft Windows 6.0 SDK. Now the SOAP services are described as a set of WSDL files, and the definitions in these WSDL files use datatypes and exceptions defined in a set of XSD files. The XSDs are shared among the WSDL files. The URLs stored in the WSDL files were intentionally wrong (security by obfuscation it seems), and wsdl.exe was having problems with them anyway so I downloaded them all.
I tried to run the tool like so:
wsdl.exe /o:myProxy.cs /n:MyNamespace some.wsdl
The first problem was errors of the kind:
Error: Unable to import binding 'CustomersBinding' from namespace 'http://customers.namespaceX.com/'. - Unable to import operation 'getStuff'. - The datatype 'http://schemas.xmlsoap.org/wsdl/:stuff1' is missing.
Now I’m far from being an expert on WSDL, but I understand the general concepts of XML namespaces and types that I thought of taking a look inside the WSDL and seeing what XSD files it imports.
After some trial and error, adding XSD files used by the WSDL file onto the end of the command did the trick for most of the WSDL files:
wsdl.exe /o:myProxy.cs /n:MyNamespace some.wsdl a.xsd b.xsd (etc..)
Now the errors caused by “The datatype blah could not be found” were mostly solved, but still I had the same problem with two WSDLs.
Digging deeper into the troublesome WSDLs I noticed that they imported types from an XSD, and used those types assuming they were imported into the default namespace http://schemas.xmlsoap.org/wsdl/ (excerpt from WSDL):
<xs:element name="getMoreStuffResponse"> <xs:complexType> <xs:sequence> <xs:element name="return" type="stuffResponse" minOccurs="1" maxOccurs="1"> etc ..
stuffResponse doesn’t have a leading namespace specifier like “xy:”, so as I understand it wsdl.exe will look for it in the WSDLs default namespace.
The section of the WSDL incidentally looked like this (with the XSD import in question in bold):
<xs:schema targetNamespace="http://customer.namespace1.xy/"> <xs:import schemaLocation="x.xsd"/> <xs:import namespace="http://customer.namespace2.xy/" schemaLocation="b.xsd"/> etc ..
The boldface import doesn’t have a namespaceattribute. Looking into x.xsd, the XSD in question where the type stuffResponse is defined:
<xs:schema version="1.0"> <xs:complexType name="stuffResponse"> etc ..
No namespace is defined. Very strange. You would have thought this should work. I didn’t have the time or inclination to figure out exactly what the problem was, so more trial and error followed.
In the end I just pasted the entire troublesome XSD file into the tag of the WSDL, and it worked perfectly. My only regret is the hours wasted on figuring out this. By the way it also turns out, of course, that even though the URLs in the WSDLs may be wrong, you can always just set the Url property on the generated proxy object later. In hindsight it seems to easy, but at the time it was just frustrating. Anyhow the saga had a good outcome after all.