Search code examples
c#.netdatacontractserializerxml-deserialization

How can I deserialize an XML, when I only know the type of an ancestor class?


Let's assume I want to deserialize this (I've removed the namespaces to make things simpler):

<TextField>
  <Caption>Location</Caption>
  <Name>Location</Name>
</TextField>

TextField inherits from FormField, so in my class definition of FormField looks something like this:

[KnownType(typeof(TextField))]
[DataContract(Name = "FormField"]
public abstract class FormField
{
    [DataMember]
    public string Name { get; set; }
}

TextField class looks like this:

[DataContract(Name = "TextField")]
public class TextField : FormField
{
    [DataMember]
    public string Caption { get; set; }
}

I tried deserializing using this:

internal static FormField Deserialize(string xml)
{
    var serializer = new DataContractSerializer(typeof(FormField)});
    using (var backing = new StringReader(xml))
    {
        using (var reader = new XmlTextReader(backing))
        {
            return serializer.ReadObject(reader) as FormField;
        }
    }
}

I get a SerializationException: "Expecting element 'FormField'..."


Solution

  • To solve my problem I added a container node to the XML, so that it looks like this:

    <FormFieldContainer>
        <TextField>   
            <Caption>Location</Caption>
            <Name>Location</Name>
        </TextField>
    </FormFieldContainer>
    

    I created this class:

    [DataContract(Name = "FormFieldContainer")]
    internal class FormFieldContainer
    {
        [DataMember]
        internal FormField FormField { get; set; }
    }
    

    And my deserialize method looks like this:

        internal static FormField Deserialize(string xml)
        {
            var serializer = new DataContractSerializer(typeof(FormFieldContainer));
            using (var backing = new StringReader(xml))
            {
                using (var reader = new XmlTextReader(backing))
                {
                    return ((FormFieldContainer)serializer.ReadObject(reader)).FormField;
                }
            }
        }
    

    If anyone has a better solution, please share it :)