logo
  • Jobs
  • About Me
  • Contact
  • Home
« Life at 31
Mozilla Firefox »

Serializing an IDictionary object

Posted June 14th, 2004 by Matt Berther

As of late, I really try to stay away from the XmlSerializer object, as I have found its limitations to be quite hindering in a lot of things I try to do.

One of the major drawbacks to this class is the serialization of an IDictionary based object. Every time that I need to do this, I end up looking towards Aaron Skonnard’s column in the MSDN Magazine.

He details a fairly simple implementation that allows you to serialize an IDictionary by wrapping it in a custom object that implements IXmlSerializable.

I took his code and added a few convenience methods and present them here (mostly for my reference later). Enjoy!

class DictionarySerializer : IXmlSerializable
{
    private IDictionary dictionary;
 
    public DictionarySerializer()
    {
        this.dictionary = new Hashtable();
    }
 
    private DictionarySerializer(IDictionary dictionary)
    {
        this.dictionary = dictionary;
    }
 
    public static void Serialize(IDictionary dictionary, Stream stream)
    {
        DictionarySerializer ds = new DictionarySerializer(dictionary);
        XmlSerializer xs = new XmlSerializer(typeof(DictionarySerializer));
        xs.Serialize(stream, ds);
    }
 
    public static IDictionary Deserialize(Stream stream)
    {
        XmlSerializer xs = new XmlSerializer(typeof(DictionarySerializer));
        DictionarySerializer ds = (DictionarySerializer)xs.Deserialize(stream);
        return ds.dictionary;
    }
 
    XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }
 
    void IXmlSerializable.ReadXml(XmlReader reader)
    {
        reader.Read();
        reader.ReadStartElement("dictionary");
        while (reader.NodeType != XmlNodeType.EndElement)
        {
            reader.ReadStartElement("item");
            string key = reader.ReadElementString("key");
            string value = reader.ReadElementString("value");
            reader.ReadEndElement();
            reader.MoveToContent();
            dictionary.Add(key, value);
        }
        reader.ReadEndElement();
    }
 
    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement("dictionary");
        foreach (object key in dictionary.Keys)
        {
            object value = dictionary[key];
            writer.WriteStartElement("item");
            writer.WriteElementString("key", key.ToString());
            writer.WriteElementString("value", value.ToString());
            writer.WriteEndElement();
        }
        writer.WriteEndElement();
    }
}

This entry was posted on Monday, June 14th, 2004 at 3:20 pm and is filed under Uncategorized. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

sachin
February 25th, 2005

bvx

Jony
March 17th, 2005

Dredging up an old post here, but just in case anybody stumbles across it through google as I did:

this code, like Aaron’s code that it comes from, is missing a

reader.ReadEndElement()

in the ReadXml method (the one that closes the dictionary tag). This can stop it from working in situations where the serialized dictionary is part of a larger object graph.

Matt Berther
March 17th, 2005

You’re absolutely correct, Jony. Thanks for the heads-up. I’ve updated the code listing.

Dave J Smith
May 9th, 2006

For those who are struggling to find the correct namespaces:

using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Collections;
using System.IO;

are required.
Dave.

Victor Bartel
May 31st, 2006

Greetings,

Thank you for this wonderful article, it helped me so much. I permit me ask you about one problem that I’ve meet. I use .NET 1.1, your class works correctly in web methods, but I have a problem to pass Serialized HashTable from web method to some asp .net application, using web references. When VS environment generate proxy class, it define your DictionarySerializer like a DataSet. For example for next web method:

[Webmethod]
public DictionarySerializer Test()
{
………
return new DictionarySerializer(MyHashTable);
}

VS will generate something like that in a proxy class:

public System.Data.DataSet Test() {
object[] results = this.Invoke(”Test”, new object[0]);
return ((System.Data.DataSet)(results[0]));
}
Without a schema specification the system define serializeble object like a DataSet. What I need to correct this problem, can you help me to do that? Thank you in advance.

Best regards
Victor Bartel

Daniel
May 4th, 2007

hi, i have this class, which has all the collection properties and methods. in it i have a property, Total, which returns the number of elements.
public class PostcodeCollection : CollectionBase
{

// .... other collection's stuff

[XmlAttribute( "Total" )]
public int Total
{
get { return List.Count; }
set
{}
}

}

this collection is a property in another class:

[XmlRoot("PostCodes" )]
public class PostcodeReport
{
// …other properties

[XmlArray("Updated")]
[XmlArrayItem(typeof(PostCodeLine), ElementName="PostCode")]
public PostcodeCollection Updated
{
get { return this.updated; }
}
}

i serialize the collection, and all is ok, but i want to add the “Total” property to the xml:
This is how the xml must look like:

i don’t know how to apply your example, any thoughts?
thanks,
Daniel

Daniel
May 4th, 2007

this is the xml, i don’t know why it wasn’t saved:

This is how the xml must look like:

Daniel
May 4th, 2007

Wil
October 4th, 2007

The serialization loses what I would consider one of the main advantages of the Hashtable and that is the type of the value.

A DateTime value is deserialized as a string and not a DateTime.

Simon
October 10th, 2007

Everything being serialized as a string, and the non-recursive nature of the serialization make this kind of useless. I’ve ended up writing a couple of helper methods that will serialize and deserialize nested IDictionary objects too.


public static StringBuilder Serialize(StringBuilder sb, object obj)
{
if (typeof(IDictionary).IsAssignableFrom(obj.GetType()))
{
sb.Append("");
foreach (object key in ((IDictionary)obj).Keys)
{
sb.Append("");
Serialize(sb, ((IDictionary)obj)[key]);
sb.Append(”");
}
sb.Append(”");
}
else
{
StringWriter sw = new StringWriter(sb);
XmlSerializer xs = new XmlSerializer(obj.GetType());
sb.Append(”");
//need a bodge in here to deal with unnamed datatables
xs.Serialize(sw, obj);
sb.Append(”");
}

return sb.Replace(”", “”);
}

public static object Deserialize(string s)
{
Object obj = new Object();

XmlDocument xml = new XmlDocument();
xml.LoadXml(s);

XmlNode node = xml.ChildNodes[0];
if (node.Name.Contains(”IDictionary_”))
{
obj = Activator.CreateInstance(Type.GetType(XmlConvert.DecodeName(node.Name.Replace(”IDictionary_”, “”))));
foreach (XmlNode child in node.ChildNodes)
((IDictionary)obj).Add(child.Name.Replace(”Key_”, “”), Deserialize(child.InnerXml));
}
else if (node.Name.Contains(”Type_”))
{
StringReader sr = new StringReader(”" + node.InnerXml);
XmlSerializer xs = new XmlSerializer(Type.GetType(XmlConvert.DecodeName(node.Name.Replace(”Type_”, “”))));
obj = xs.Deserialize(sr);
}

return obj;
}

Use it like this:

Hashtable ht1 = new Hashtable();
ht1["1"] = 1;
ht1["2"] = 2;

Hashtable ht2 = new Hashtable();
ht2["a"] = “a”;
ht2["b"] = “b”;

ht1["3"] = ht2;

Serialize(new StringBuilder(), ht1);

Simon
October 10th, 2007

Hmm, that comment has mangled some of the XML tags that were in the code, the method won’t work as it is shown on this page

Nikhil Shah
March 21st, 2008

This works very well,
gooood work ,
data gets serialized successfully,
but does not gets deserialize !!!
my problem is smwht like this, I have Four hashtable that stores the key n value pair,
on Form I have 4 combobox n 4 respective textbox ,
I wnt to populate the Key in combobx n Its RESPECTIVE value in textbox
on the selectedindex event of the combx, I where I write a code
I gets an error, tht there is a problem with XML document !!!
this XMl doc is well-formed, No-bugs thr..
this means tht the data is nt deserializing …

If you get this, plz help me out m stuck in this prblm since last 2 days :(

pepz
June 21st, 2008

I think the function ‘ReadXml’ needs an extra function call to ‘reader.ReadEndElement()’ to fully close out the working node. This should allow it to work within larger object graphs as well.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
-->

Social
  • mattberther on twitter
Syndication
Archives
  • August 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • November 2007
  • October 2007
  • September 2007
  • August 2007
  • July 2007
  • June 2007
  • May 2007
  • April 2007
  • March 2007
  • February 2007
  • January 2007
  • December 2006
  • November 2006
  • October 2006
  • September 2006
  • August 2006
  • July 2006
  • June 2006
  • May 2006
  • April 2006
  • March 2006
  • February 2006
  • January 2006
  • December 2005
  • November 2005
  • October 2005
  • September 2005
  • August 2005
  • July 2005
  • June 2005
  • May 2005
  • April 2005
  • March 2005
  • February 2005
  • January 2005
  • December 2004
  • November 2004
  • October 2004
  • September 2004
  • August 2004
  • July 2004
  • June 2004
  • May 2004
  • April 2004
  • March 2004
  • February 2004
  • January 2004
  • December 2003
  • November 2003
  • October 2003
  • September 2003
  • August 2003
  • July 2003
  • June 2003
  • May 2003
  • April 2003
  • March 2003
Jobs
mattberther.com © 2003 - 2008