I've run into a few gotchas when doing C# XML serialization that I thought I'd share:
- You can't serialize items that are read-only (like KeyValuePairs)
- You can't serialize a generic dictionary. Instead, try this wrapper class (from http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx):
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
bool wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty)
return;
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
reader.ReadStartElement("item");
reader.ReadStartElement("key");
TKey key = (TKey)keySerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement("value");
TValue value = (TValue)valueSerializer.Deserialize(reader);
reader.ReadEndElement();
this.Add(key, value);
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
foreach (TKey key in this.Keys)
{
writer.WriteStartElement("item");
writer.WriteStartElement("key");
keySerializer.Serialize(writer, key);
writer.WriteEndElement();
writer.WriteStartElement("value");
TValue value = this[key];
valueSerializer.Serialize(writer, value);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
}
Any other XML Serialization gotchas out there?
I can't make comments yet, so I will comment on Dr8k's post and make another observation. Private variables that are exposed as public getter/setter properties, and do get serialized/deserialized as such through those properties. We did it at my old job al the time.
One thing to note though is that if you have any logic in those properties, the logic is run, so sometimes, the order of serialization actually matters. The members are implicitly ordered by how they are ordered in the code, but there are no guarantees, especially when you are inheriting another object. Explicitly ordering them is a pain in the rear.
I've been burnt by this in the past.
Oh here's a good one: since the XML serialization code is generated and placed in a separate DLL, you don't get any meaningful error when there is a mistake in your code that breaks the serializer. Just something like "unable to locate s3d3fsdf.dll". Nice.
Be careful serialising types without explicit serialisation, it can result in delays while .Net builds them. I discovered this recently while serialising RSAParameters.
You may face problems serializing objects of type Color and/or Font.
Here are the advices, that helped me:
http://www.codeproject.com/KB/XML/xmlsettings.aspx
http://www.codeproject.com/KB/cs/GenericXmlSerializition.aspx
I can't really explain this one, but I found this won't serialise:
but this will:
And also worth noting that if you're serialising to a memstream, you might want to seek to 0 before you use it.
Another huge gotcha: when outputting XML through a web page (ASP.NET), you don't want to include the Unicode Byte-Order Mark. Of course, the ways to use or not use the BOM are almost the same:
BAD (includes BOM):
GOOD:
You can explicitly pass false to indicate you don't want the BOM. Notice the clear, obvious difference between
Encoding.UTF8
andUTF8Encoding
.The three extra BOM Bytes at the beginning are (0xEFBBBF) or (239 187 191).
Reference: http://chrislaco.com/blog/troubleshooting-common-problems-with-the-xmlserializer/