Internally, according to the docs, the state server uses BinaryFormatter to serialize complex types. BinaryFormatter serializes all public and private fields (not properties!) of a class or struct that is marked as [Serializable]. But XmlDocument, as you have noted, is not so marked, thus cannot be immediately serialized with BinaryFormatter.
XmlDocument can, however, be trivially converted from and to a string -- the XML itself that the document represents. Thus if the XmlDocument field were contained in a type implementing ISerializable, then its GetObjectData() could simply store the corresponding XML string inside the serialization stream. Then the corresponding serialization constructor could extract the XML string and reconstitute the XmlDocument.
Since implementing ISerializable on a pre-existing class can be time consuming, the easiest way to accomplish what you want would be to introduce a small serialization wrapper struct for your XML documents:
[Serializable]
public struct XmlDocumentSerializationWrapper : ISerializable
{
public static implicit operator XmlDocumentSerializationWrapper(XmlDocument data) { return new XmlDocumentSerializationWrapper(data); }
public static implicit operator XmlDocument(XmlDocumentSerializationWrapper wrapper) { return wrapper.XmlDocument; }
private readonly XmlDocument xmlDocument;
public XmlDocument XmlDocument { get { return xmlDocument; } }
public XmlDocumentSerializationWrapper(XmlDocument xmlDocument)
{
this.xmlDocument = xmlDocument;
}
public XmlDocumentSerializationWrapper(SerializationInfo info, StreamingContext context)
{
var xml = (string)info.GetValue("XmlDocument", typeof(string));
if (!string.IsNullOrEmpty(xml))
{
xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xml);
}
else
{
xmlDocument = null;
}
}
#region ISerializable Members
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
if (XmlDocument != null)
{
var xml = XmlDocument.OuterXml;
info.AddValue("XmlDocument", xml);
}
else
{
info.AddValue("XmlDocument", (string)null);
}
}
#endregion
}
Then, in the classes you want to serialize, replace your XmlDocument fields (and auto-implemented properties) with wrapper struct fields, e.g.:
[Serializable]
public class TestClass
{
XmlDocumentSerializationWrapper doc;
public XmlDocument Document { get { return doc; } set { doc = value; } }
}
The implicit operators in the struct handle automatic conversion from and to the wrapper.