2

I'm having severe headaches trying to deserialize an XML into an auto-generated proxy class with derived types.

This is my scenario (working with Xml.Serialization)

One WCF 4.0 service sharing (as part of the contract) these type:

[XmlRootAttribute(Namespace = "", IsNullable = false)]
public class InstallerConfig
{
    [XmlArray]
    [XmlArrayItem(typeof(FileExistsRequisite))]
    [XmlArrayItem(typeof(RegistryKeyExistsRequisite))]
    public List<ModuleRequisite> Prerequisites { /* getter and setter */ }

    ...
}

FileExistsRequisite and RegistryKeyExistsRequisite are both derived from base ModuleRequisite. All of them are defined as follows:

[XmlInclude(typeof(FileExistsRequisite))]
[XmlInclude(typeof(RegistryKeyExistsRequisite))]
public class ModuleRequisite
{
    /* some properties here */
}

public class FileExistsRequisite : ModuleRequisite
{
    /* some properties here */
}

public class RegistryKeyExistsRequisite : ModuleRequisite
{
    /* some properties here */
}

If I try to serialize and then deserialize an InstallerConfig instance it just work (both serialization and deserialization work as expected).

This is the resultant XML file:

<?xml version="1.0" encoding="utf-8"?>
<InstallerConfig xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Prerequisites>
        <RegistryKeyExistsRequisite>
            <RequisiteOrder>1</RequisiteOrder>
            <!-- Some other elements with their values -->
        </RegistryKeyExistsRequisite>
        <FileExistsRequisite>
            <RequisiteOrder>2</RequisiteOrder>
            <!-- Some other elements with their values -->
        </FileExistsRequisite>
    </Prerequisites>
</InstallerConfig>

However, in the other hand I have a NET 2.0 WinForms Application with WCF referenced by a web reference. When I try to deserialize previously serialized XML file:

XmlSerializer serializer = new XmlSerializer(typeof(WCFWebReference.InstallerConfig));
XmlTextReader stream = new XmlTextReader("deserializedXML.xml");
WCFWebReference.InstallerConfig desInstallerConfig = (WCFWebReference.InstallerConfig)serializer.Deserialize(stream);

Created desInstallerConfig object has an empty array of ModuleRequisite objects (MyNamespace.WCFWebReference.ModuleRequisite[0]) as value for Prerequisite field, when XML actually has two elements both derived from ModuleRequisite.

What am I doing wrong? So much frustrated with this trouble :-(

Thanks in advance.

HiseaSaw
  • 165
  • 1
  • 1
  • 11
  • Can you clarify what you mean by "One WCF 4.0 service sharing these type" ? Do you mean that `InstallerConfig` is part of the contract or do you mean the client actually references the same DLL which contains `InstallerConfig` as the service? If the former then then `InstallerConfig` seen by the client is a new class built from a definition passed by the service - not your original class so will be missing the attributes. – Basic Apr 18 '11 at 13:21
  • So, you have two applications, and the de-serialization of the XML works in one of them, and not in the other. Is that right? – Cheeso Apr 18 '11 at 13:28
  • @Basiclife : I'm sorry, meant that InstallerConfig is part of the contract. But this loss of attributes info happens only with derived property types. In fact am using other generic and non generic collections (ommited here) for InstallerConfig properties, and I get them successfully serialized and deserialized. – HiseaSaw Apr 18 '11 at 13:51
  • @Cheeso that's it. Deserialization works properly at WCF side but not at client side – HiseaSaw Apr 18 '11 at 13:52
  • If you right-click then `Go To Definition` on `InstallerConfig` in the client-side app, is there anything obviously wrong with the class? Does it have all the attributes/properties you expect? Is i identical to the WCF-side equivalent? – Basic Apr 18 '11 at 14:03
  • @Basiclife Yes, it's. All XmlInclude tags are included (with `SoapIncludeAttribute`), and all inheritance has been properly auto-generated. Furthermore, base class are declared prior to derived classes in `Reference.cs` class (I read somewhere this is a must). – HiseaSaw Apr 18 '11 at 14:09

1 Answers1

0

I solved my problem.

First, I removed ALL XML decoration tags from Prerequisites property in InstallerConfig class. That made that, after serialization, elements from derived classes in XML not appearing as <DERIVEDCLASSNAME></DERIVEDCLASSNAME>, but as <BASECLASSNAME xsi:type="DERIVEDCLASSNAME"></BASECLASSNAME>.

At client, when deserializing, I added derived classes as extra types in XmlSerializer constructor:

List<Type> extraTypes = new List<Type>() {
    extraTypes.Add(typeof(WCFWebReference.FileExistsRequisite)),
    extraTypes.Add(typeof(WCFWebReference.RegistryKeyExistsRequisite))
};
XmlSerializer serializer = new XmlSerializer(
    typeof(WCFWebReference.InstallerConfig), extraTypes.ToArray());

That let the application code to cast any ModuleRequisite derived class to its corresponding type (defined in xsi:type XML property).

HiseaSaw
  • 165
  • 1
  • 1
  • 11