Search code examples
c#xmlserializationdatacontractserializer

DataContractSerializer produces XML with no child nodes, preserves no data


I've been reading StackOverflow forever, but finally ran into something for which the internet appears to have no existing answer. Upon discovering that an XMLSerializer cannot serialize dictionaries, I switched over to a DataContractSerializer. Problem is, serialization quietly fails no matter how I handle it. Here's what I'm trying to serialize. It is highly-simplified (I was trying to narrow the problem down), but suffers from the same malady as its more complex forefathers:

[DataContract(Namespace = "")]
public class TestData
{
    public Dictionary<Enum1, List<string>> List1 = new Dictionary<Enum1, List<string>>();

    public DateTime WeekStarting { get; private set; }
    public DateTime LastSaved { get; set; }
    public int Iteration { get; set; }

    public string FilePath { get; private set; }
    public string FileName { get; private set; }

    public TestData()
    {
        FilePath = "C:/";
        FileName = "whatever.xml";

        foreach (var category in Enum.GetValues(typeof(Enum1)).Cast<Enum1>())
        {
            List1.Add(category, new List<string>());
        }

        LastSaved = DateTime.Now;
        WeekStarting = DateTime.Now;
        Iteration = 0;
    }
}

I initially tried using this code to serialize it:

var serializer = new DataContractSerializer(typeof(TestData));
using (var writer = new XmlTextWriter(File.CreateText(Path.Combine(CurrentWeek.FilePath, CurrentWeek.FileName))))
{
    writer.Formatting = Formatting.Indented;
    serializer.WriteObject(writer, currentWeek);
}

After looking at similar issues around Stackoverflow (completely empty output, unlike mine), I've also tried this:

var serializer = new DataContractSerializer(typeof(TestData));
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, CurrentWeek);
ms.Position = 0;

string serializedContent;
using (StreamReader sr = new StreamReader(ms))
{
    serializedContent = sr.ReadToEnd();
}

And this:

var serializer = new DataContractSerializer(typeof(TestData));
using (var sw = new StringWriter())
{
    using (var writer = new XmlTextWriter(sw))
    {
        writer.Formatting = Formatting.Indented;
        serializer.WriteObject(writer, CurrentWeek);
        writer.Flush();
        var xmlString = sw.ToString();
    }
}

All of which produced an XML file solely containing this:

<TestData xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />

...an XML which contains something, but is essentially empty as it didn't serialize any of TestData's content. Loading this up and performing operations on it will cause all sorts of bad things to happen in my program. Things weren't going any better when it had a namespace. Anyone have any ideas?


Solution

  • You need to mark the properties you wish to serialize with the [DataMember] attribute. From the documentation for DataContractAttribute

    Apply the DataContractAttribute attribute to types (classes, structures, or enumerations) that are used in serialization and deserialization operations by the DataContractSerializer.

    You must also apply the DataMemberAttribute to any field, property, or event that holds values you want to serialize. By applying the DataContractAttribute, you explicitly enable the DataContractSerializer to serialize and deserialize the data.

    Also, if you want to serialize your Dictionary<Enum1, List<string>>, you need to mark your enum Enum1 with [DataContract] (probably with namespace [DataContract(Namespace="")]) and each enum member with [EnumMember]. More here: Enumeration Types in Data Contracts.