Search code examples
c#serializationdatacontractserializerdatacontract

C# Serialization, alternative set of DataMember(Name=) attributes


I'm serializing my DTO to XML messages using DataContractSerializer, however I need to support 2 XML formats, they are identical in structure but differ in element naming, so I need to support an alternative set of DataMemeber[Name=""] attributes on my DTO's. How to solve this without cloning my DTO classes? I need to support both formats at runtime, so preproccessor derectives will not suffice.


Solution

  • Firstly, for fine-grained xml serialization, XmlSerializer is preferable to DataContractSerializer (which is fine as a general purpose serializer, but is hard to take seriously as an xml serializer when it can't even handle attributes).

    Secondly, XmlSerializer has options for this - in particalar, XmlAttributeOverrides. With an XmlAttributeOverrides you can configure the entire setup for your type at runtime, then just pass it in to the XmlSerializer constructor. Important warning: do this once and store the serializer instance, otherwise you will haemorrhage dynamic assemblies.

    [XmlRoot("foo")]
    public class Foo
    {
        [XmlElement("bar")]
        public string Bar { get; set; }
    }
    class Program
    {
        static void Main()
        {
            XmlAttributeOverrides xao = new XmlAttributeOverrides();
            xao.Add(typeof(Foo), new XmlAttributes { XmlRoot =
                   new XmlRootAttribute("alpha")});
            xao.Add(typeof(Foo), "Bar", new XmlAttributes { XmlElements = {
                   new XmlElementAttribute("beta") } });
            var ser = new XmlSerializer(typeof (Foo), xao);
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("","");
            ser.Serialize(Console.Out, new Foo { Bar = "abc"}, ns);
        }
    }
    

    with output:

    <alpha>
      <beta>abc</beta>
    </alpha>