It seems there is a known bug in wsdl.exe, the tool that Visual Studio uses to generate web service proxies. With certain XSD schemas the tool will generate classes that can't be deserialized from the XML.
As far as I'm concerned that's unacceptable, but I don't know how to fix it.
I will describe my case in detail, hopefully somebody will be able to help me with it.
Schema
<!-- return type from the service operation -->
<xs:complexType name="listAssetsQueryResults">
<xs:sequence>
<xs:element name="assets" type="tns:asset" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<!-- a sequence of attributes -->
<xs:complexType name="asset">
<xs:sequence>
<xs:element name="attributes" type="tns:multiValuedAttribute" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="multiValuedAttribute">
<!-- not relevant-->
</xs:complexType>
XML response from the webservice
A typical response according to this schema looks like this:
<assets-query-result>
<assets>
<attributes>
<name>Keywords</name>
<values>Desert</values>
</attributes>
<attributes>
<name>Filename</name>
<values>Desert.jpg</values>
</attributes>
</assets>
<assets>...</assets>
<assets>...</assets>
</assets-query-result>
Using the types in code
I would have expected to be able to use the CLR types like this:
result.assets[0].attributes[0].name
Instead, the generated type for the result looks like this:
[SerializableAttribute()]
public partial class listAssetsQueryResults {
private multiValuedAttribute[][] assetsField;
[XmlArrayAttribute(Form=XmlSchemaForm.Unqualified, IsNullable=true)]
[XmlArrayItemAttribute("attributes", typeof(multiValuedAttribute), Form=XmlSchemaForm.Unqualified)]
public multiValuedAttribute[][] assets {
get { return this.assetsField; }
set { this.assetsField = value; }
}
}
Which doesn't even allow the serialization assembly to be generated!
Unable to convert type Portfolio.WebService.multiValuedAttribute to Portfolio.WebService.multiValuedAttribute[]
Fixing it
1 - Changing the type of the property and field
Now one of the fixes I found online is simply to remove one pair of brackets from the type of the generated property:
// No longer a jagged array, but this doesn't deserialize all data
public multiValuedAttribute[] assets;
That allows the serialization assembly to be built, and it runs without exceptions, except it doesn't serialize the data correctly, it 'skips' the list of assets and deserializes the attributes of the first assets
element. So it's not a fix at all, because with this fix I can't consume the data. For 700+ assets it gives result.assets
is equal to multiValuedAttribute[2]
(the 2 elements are the name and keywords attributes of the first asset).
2 - Specifying the type of the XML-elements
The second thing I tried is to give the deserializer different instructions:
[XmlArrayItemAttribute("attributes", typeof(multiValuedAttribute[]), Form=XmlSchemaForm.Unqualified)]
public multiValuedAttribute[][] assets { ... }
So now I'm telling it that each element in the sequence is of type multiValuedAttribute[]
. That's wrong because it's still looking at attributes
elements, which are of type multiValuedAttribute
(single, not an array). It does run however, but now the result.assets
is equal to multiValuedAttribute[2][0]
and I'm still not able to get to the data.
What's next?
I have no idea, which is why I wrote this. I can't accept that .NET is not able to consume this web service, because it has to.