Search code examples
c#serializationdatacontractserializer

Unable to deserialize property with specific name


I'm using DataContractSerializer in C# to deserialize xml file into object, and everything was working fine :)

My issue started when I add a new property to my class and xml file. My new property name is EncryptionKey every time I deserialize file, property value remain null, but when i change the name of xml element and property to anEncryptionKey it deserialized correctly without changing anything else in the code.

Actually I try a lot of options for property name like EncryptKey, Encrypt and a lot more but I ended up with anEncryptionKey.

Maybe there is some constraint on properties names or something like that or I just need more caffeine to figure it out.

Xml file:

<?xml version="1.0" encoding="utf-8" ?>
<KioskSettings xmlns="http://schemas.datacontract.org/2004/07/Proxies" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <ID>20198</ID>
  <HeartBeatInterval>1</HeartBeatInterval>
  <ServerURL></ServerURL>
  <EncryptionKey>abcd</EncryptionKey>
</KioskSettings>

Code i use to deserialize file into object:

private KioskSettings ReadEngineSettingsFromSimulatorXmlFile()
 {
    KioskSettings engineSettings = new KioskSettings();
    DataContractSerializer serializer = new DataContractSerializer(typeof(KioskSettings));
    FileStream fs = new FileStream(@"c:\simulation.xml", FileMode.Open);
    XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
    while (reader.Read())
    {
        switch (reader.NodeType)
        {
            case XmlNodeType.Element:
                if (serializer.IsStartObject(reader))
                {
                    engineSettings = (KioskSettings)serializer.ReadObject(reader);
                }
                break;
        }
    }

    fs.Flush(); fs.Close();
    reader.Close(); 
    reader = null;
    serializer = null;
    return engineSettings;
}

KioskSettings class:

 public class KioskSettings
 {
    public string ID { get; set; }

    public int HeartBeatInterval {get; set;}

    public string ServerURL {get; set;}

    public string EncryptionKey { get; set; }

 }

Note: Above code may contains some syntax errors because I modify it to make it short.


Solution

  • You need to ensure your XML nodes are in alphabetical order:

    <?xml version="1.0" encoding="utf-8" ?>
    <KioskSettings xmlns="http://schemas.datacontract.org/2004/07/Proxies" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      <EncryptionKey>abcd</EncryptionKey>
      <HeartBeatInterval>1</HeartBeatInterval>
      <ID>20198</ID>
      <ServerURL></ServerURL>
    </KioskSettings>
    

    Serialize a KioskSettings object with the following code, and ensure your XML takes the same form:

    public static string DataContractSerializeObject<T>(T objectToSerialize)
    {
        using (MemoryStream memStm = new MemoryStream())
        {
            var serializer = new DataContractSerializer(typeof(T));
            serializer.WriteObject(memStm, objectToSerialize);
    
            memStm.Seek(0, SeekOrigin.Begin);
    
            using (var streamReader = new StreamReader(memStm))
            {
                string result = streamReader.ReadToEnd();
                return result;
            }
        }
    }
    

    If you need to preserve a specific order then specify the DataMember attribute on your class properties - Data Member Order e.g.

    [DataContract]
    public class KioskSettings
    {
        [DataMember(Order = 1)]
        public string ID { get; set; }
    
        [DataMember(Order = 2)]
        public int HeartBeatInterval { get; set; }
    
        [DataMember(Order = 3)]
        public string ServerURL { get; set; }
    
        [DataMember(Order = 4)]
        public string EncryptionKey { get; set; }
    }