Search code examples
c#xml-serialization

C# - Xml Deserialization of KeyValueConfigurationCollection


I have a C# app. In this app, I have some XML that looks like this:

string xml = @"<list name=""Groceries"">
  <add key=""1"" value=""Milk"" />
  <add key=""2"" value=""Eggs"" />
  <add key=""3"" value=""Bread"" />
</list>";

I'm trying to convert this XML into a C# object. My class looks something like this:

public class List : ConfigurationElement, IXmlSerializable
{
  [ConfigurationProperty("name", IsRequired = true, IsKey = true, DefaultValue = "")]
  public string Name
  {
    get { return (string)(this["name"]); }
    set { this["name"] = value; }
  }

  [ConfigurationProperty("", IsRequired = false, IsKey = false, 
IsDefaultCollection=true)]
  public KeyValueConfigurationCollection Items
  {
    get
    {
      var items = base["items"] as KeyValueConfigurationCollection;
      return items;
    }
    set
    {
      if (base.Properties.Contains("items"))
      {
        base["items"] = value;
      }
      else
      {
        var configProperty = new ConfigurationProperty("items", typeof(KeyValueConfigurationCollection), value);
        base.Properties.Add(configProperty);
      }
    }
  }

  public XmlSchema GetSchema()
  {
    return this.GetSchema();
  }

  public void ReadXml(XmlReader reader)
  {
    this.DeserializeElement(reader, false);
  }

  public void WriteXml(XmlWriter writer)
  {
    this.SerializeElement(writer, false);
  }

    public static List Deserialize(string xml)
    {
        List list= null;

        var serializer = new XmlSerializer(typeof(List));
        using (var reader = new StringReader(xml))
        {
            list = (List)(serializer.Deserialize(reader));
        }

        return list;
    }

}

When I run var list = List.Deserialize(xml); I get a List object back. The name of the List is properly set. However, the Items property is null. Why aren't the Items getting deserialized? How do I get the Items populated with the key/value pairs listed?

Thank you


Solution

  • Looks like duplicate to earlier question.

    Here are corrections:

    • Removed "items" from getter, otherwise it throws

    System.Configuration.ConfigurationErrorsException: 'The property 'Items' must not return null from the property's get method. Typically the getter should return base[""].'

    get
            {
                var items = base[""] as KeyValueConfigurationCollection;
                return items;
            }
    
    • Updated serializer with root attribute:

    public static List Deserialize(string xml)
        {
            var serializer = new XmlSerializer(typeof(List), new XmlRootAttribute("list"));
            List list = null;
    
            var xdoc = XDocument.Parse(xml);
            list = (List)serializer.Deserialize(xdoc.CreateReader());
            return list;
        }
    

    Final version now reads as follows:

    public class List : ConfigurationElement, IXmlSerializable
    {
        public List()
        { }
    
        [ConfigurationProperty("name", IsRequired = true, IsKey = true, DefaultValue = "")]
        public string Name
        {
            get { return (string)(this["name"]); }
            set { this["name"] = value; }
        }
    
        [ConfigurationProperty("", IsRequired = false, IsKey = false,
      IsDefaultCollection = true)]
        public KeyValueConfigurationCollection Items
        {
            get
            {
                var items = base[""] as KeyValueConfigurationCollection;
                return items;
            }
            set
            {
                if (base.Properties.Contains("items"))
                {
                    base["items"] = value;
                }
                else
                {
                    var configProperty = new ConfigurationProperty("items", typeof(KeyValueConfigurationCollection), value);
                    base.Properties.Add(configProperty);
                }
            }
        }
    
        public XmlSchema GetSchema()
        {
            return this.GetSchema();
        }
    
        public void ReadXml(XmlReader reader)
        {
            this.DeserializeElement(reader, false);
        }
    
        public void WriteXml(XmlWriter writer)
        {
            this.SerializeElement(writer, false);
        }
    
        public static List Deserialize(string xml)
        {
            List list = null;
            var serializer = new XmlSerializer(typeof(List), new XmlRootAttribute("list"));
    
            var xdoc = XDocument.Parse(xml);
            list = (List)serializer.Deserialize(xdoc.CreateReader());
            return list;
        }
    }