Yossi Dahan [BizTalk]

Google
 

Tuesday, September 11, 2007

Web Service and inheritance problem

I suspect WSDL.exe's attempt to be too clever has hit us again - here's a (very graphic) description of what we found -

We have a set of classes that look like this -




If we create a schema for ContainerClass using XSD.exe it looks like this -




All good so far, and indeed serialization and deserialization between the two work just fine.

We’ve then created a web method that returns ContainerClass, as such -

[WebMethod]
public ContainerClass ReturnContainer()
{
ContainerClass cc = new ContainerClass();
cc.Items = new System.Collections.Generic.List();
cc.Items.Add(new Item());
cc.Items.Add(new SubItem());
cc.Items.Add(new AnotherSubItem());
return cc;
}

Looking at the rendering of the WSDL in IE it looks promising -





You can notice the WSDL tells us we will get a ContainerClass with an Items element, and in that we would get Item, Sub Item and/or AnotherSubItem as expected.

What happens if we call the web methods then? (remember that the web methods adds one of each type to the list) -
We've created a windows app, added a web reference and called the web method - here's what we've received back -




You will immediately notice that the first member added to the Items list in the web method - Item - does not appear to reach the client.

Using HTTP analyser we've sniffed for the stream coming back from the web service, and it did contain all three members, the "Item" one was removed in the serialisation from the stream to the class.

As we've tested the serialisation before, we knew it should work, so we had to look at the proxy generated - and this is when the problem became apparent - here's the relevant extract from the generated proxy -




WSDL exe - when generating the proxy - has "kindly" decided to remove the XmlArrayItem option we've explicitly added for "Item" and only included "SubItem" and "AnotherSubItem".
This meant that the client did not know how to deserialise the Item member of the list and it got emmitted from the deserialised class.

By adding the missing XmlArrayItemAttribute following line to the proxy we've managed to get all 3 items without touching the web service.

As this is not something we would like to do in production code we've opened a call with Microsfot to try and see what we can do, but we're obviously open to suggestions, anyone?

4 Comments:

  • Dear Yossi , I have a n Question not in this post , but about how to oublish an bizTalk 2006 Orchestration that takes an Empty Request , hope to get my question..!!!!

    By Blogger U3, at 13/09/2007, 12:32  

  • Hi U3,

    Posted an answer to your question here

    By Blogger Yossi Dahan, at 13/09/2007, 14:48  

  • Hi Yossi,

    Change the serialization paratmeter in the server as shown below.

    Original:
    [XmlArray("Items"),
    XmlArrayItem("Item",typeof(Item)), XmlArrayItem("SubItem",typeof(SubItem)), XmlArrayItem("AnotherSubItem",typeof(AnotherSubItem))]

    Modified:
    [XmlArray("Items"),
    XmlArrayItem("ItemSK",typeof(Item)), XmlArrayItem("SubItem",typeof(SubItem)), XmlArrayItem("AnotherSubItem",typeof(AnotherSubItem))]

    Also, change the XmlRoot serialization paratemeter to whatever value you set above example

    Original:
    [Serializable(),XmlType(AnonymousType=false), XmlRoot("Item")]

    Modified:
    [Serializable(),XmlType(AnonymousType=false), XmlRoot("ItemSK")]


    Now, when you look at the auto generated code at the client side (windows app) it will look like this

    [System.Xml.Serialization.XmlArrayItemAttribute(typeof(AnotherSubItem))]
    [System.Xml.Serialization.XmlArrayItemAttribute("ItemSK"]
    [System.Xml.Serialization.XmlArrayItemAttribute(typeof(SubItem))]

    What's happening in your code is, when you mention "Item" as the serializable parameter, which I guess will be the default value for the element List<Item>, the client side autogenerated code thinks it as reduntant data and quitly ignores it.

    By doing the changes I mentioned, your code should work.

    Regards,
    Saravana Kumar

    By Blogger Saravana Kumar, at 14/09/2007, 08:00  

  • Hi Saravana

    Thanks for your comment, this is quite a nice idea! i am almost upset for not thinking aboug it myself!

    The only difficult thing about this is that it changes the message on the wire, which means we will need to change our schema, which in turn means we will need to change all of the maps that use it! quite a nightmare considering the amount of re-use we have in our (rather big) implementation

    I will see what Microsoft have to say about this first, but will also consider changing the class name instead - still a lot of re-use but at least you get a compile time error.

    By Blogger Yossi Dahan, at 14/09/2007, 08:42  

Post a Comment

<< Home