Serialising to XML with C# - with Obfuscation and with Hierarchies

In C#, it is very easy to serialise your objects to and from XML.

  • just set the visibility to be public, for the types and members that you want serialised:


//public type, so that the serialiser can use it:
public class UserSettings
{
  //default constructor with no params, so that the serialiser can create it:
  public UserSettings()
  {
  }


  //public property:
  public string Name
  {
    get { return name; }
    set { name = value; }
  }
}


  • then write code like this:

using System.IO;
using System.Xml;
using System.Xml.Serialization;


...


UserSettings settings = new UserSettings();
//... populate the settings object


//now serialise settings to XML file:
string fileName = @"c:\my_usersettings.xml";
XmlSerializer xs = new XmlSerializer(typeof(UserSettings));
using(TextWriter tw = new StreamWriter(fileName))
{
xs.Serialize(tw, this);
tw.Close();
}

Problems
However, with more complex situations, which are fairly common, the XML serialisation can run into problems.

Hierarchies:
Some hierarchies will encounter a runtime error when the serialiser tries to navigate the hierarchy.  This can happen:

  • if there are circular references (for example, the typical parent-child two way reference that occurs in a Composite pattern)
Serialising a collection of base types
Say you have a base class 'Base1' and two or more derived classes 'Derived1', 'Derived2' etc.
Then say you have a collection, which contains a mixture of the derived types:
List list = new List();
list.Add(new Derived1());
list.Add(new Derived2());

The serialiser cannot handle serialising such a collection.

Complex Type - Requires Custom Serialisation:
  • some complex types require custom serialisation (for example, serialising a bitmap to a mime type)


Obfuscation:

  • if obfuscation is active (as the obfuscator will unpredictably abbreviate the type and member names, which of course will affect the XML)


Some solutions
Hierarchies:
  • before serialisation, flatten your hierarchy into a list of nodes, which use a simple string key to refer to each other.
  • after de-serialisation, restore your hierarchy, by using a hashtable populated with the simple string keys


Serialising a collection of base types
This seems to be a specific example of a more general problem, where if a public member is of a base type, then the serialiser cannot handle the case where the member refers to a derived type.
There is a good article here which provides a solution:


Custom Type - Requires custom serialisation:
There is an article on CodeProject, which uses a TypeConverter to serialise a BitMap (plus some other useful examples):
http://www.codeproject.com/KB/XML/xml_serializationasp.aspx

There is a CodeProject article here on implementing your own TypeConverter:
http://www.codeproject.com/KB/dotnet/BasicPropertyGrid.aspx

Obfuscation:
Use the Obfuscation attribute to switch off obfuscation for a particular type or member:



[Obfuscation(ApplyToMembers = true, Feature = "renaming", Exclude = true)]
public class ChangeDetection
{
...
...
    public ChangeDetection()
    {
    }


    //is serialized:
    [Obfuscation(Exclude = true)]
    [XmlAttribute("KeywordsEnabled")]
    public bool KeywordsEnabled
    {
        get
        {
            return bKeywordsEnabled;
        }
    }
...
...
}

Comments