October 22, 2012

XML Serialization

Problem

A long time ago I had to implement some data storage between restartings of application in one of my projects. I started looking for the best solution to do that and one of them using .NET Settings files (about that I`ll write in the future), another – to use serialization (I`ve chosen xml serialization because it is more human readable and flexible).
Serialization is the process of converting an object into a stream of bytes in order to store or transmit it.
Deserialization is the opposite process to serialization – converting data to object.

The most used serialization types in .NET Framework:
  • Binary serialization (is the serialization process with binary data as a result)
  • Xml serialization (is the serialization process with XML data as a result)
XML serialization approach is “cross platform”. We can serialize data in one application (for example java-based) and deserialize it in .NET app.

Want to know more about XML Serialization? Welcome...


Which class supports xml serialization?

XML Serialization uses Reflection to get data from class to generate XML.
Therefore there are next requirements for class that can be serialized to xml:
  • Class should contain public default constructor (without parameters).  
  • Only Public properties\fields are to be serialized.
  • If public property is read-only then it value cannot be restored.
In Binary serialization we make a ‘dump’ of appropriate object memory. At the time we can store all data along with private properties and fields.

Now I`ll show to you how XML Serialization is easy to use .

Let’s take a look at our test class.
    public enum Role
    {
        RegularUser,
        Administrator
    }
    public class User
    {
        public string Name { get; set; }
        public string EMail { get; set; }
        public string Password { get; set; }
        public int PasswordExpiresIn { get; set; }
        public int Age { get; set; }
        public Role UserRole { get; set; }
    }

Generic serialization and deserialization

Detailed information about XMLSerializer can be found here in msdn: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx
I prefer developing some abstract serializer which just gets some object (which will be serialized) and returns xml result. It is very flexible because we separate serialization and data saving. Thus if we need to store serialized object in database it cannot be a problem and we shouldn’t improve serialization, we should only save it.
Example:
public class Program
{
    public static void Main(string[] args)
    {
        var userToSave = new User
        {
            Name = "Rostyslav",
            Age = 24,
            Password = "123",
            EMail = "sample@email.com",
            UserRole = Role.Administrator,
        };
        var xml = XmlSerializationService<User>.Serialize(userToSave);
        Console.WriteLine(xml);          
    }
}
Result:
<User xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Name>Rostyslav</Name>
  <Email>sample@email.com</Email>
  <Password>123</Password>
  <PasswordExpiresIn>0</PasswordExpiresIn>
  <Age>24</Age>
  <UserRole>Administrator</UserRole>
</User>

Manage 'class members to xml' transformation.
If you want to manage serialization process:
  • set the field that should be stored as xml-attribute;
  • setup some another xml nodes name (instead of defaults based on members names);
You can use the attributes on your target .NET classes.
Read more about Attributes that control XML Serialization here in msdn: http://msdn.microsoft.com/en-us/library/83y7df3e(v=vs.71).aspx

Now we can store and restore our user object, but we want to change all nodes in result xml to attributes, rename EMail attribute to UserMail and do not serialize PasswordExpiresIn property because these data will be received from some another source. All that we need to do is only to set appropriate attributes to our target class.

Example:
public class User
{
    [XmlAttribute]
    public string Name { get; set; }

    [XmlAttribute(AttributeName = "UserMail")]
    public string EMail { get; set; }

    [XmlAttribute]
    public string Password { get; set; }

    [XmlIgnore]
    public int PasswordExpiresIn { get; set; }

    [XmlAttribute]
    public int Age { get; set; }

    [XmlAttribute]
    public Role UserRole { get; set; }
}

 Result:
<User xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Age="24" Name="Rostyslav" Password="123" UserMail="sample@email.com" UserRole="Administrator">
</User>

Serialization of complex/derived classes and arrays
If we derive classes or some class that contains another one XmlSerializer will work fine. Also XmlSerializer can serialize List<T> and arrays without any magic.

Example:
Result:
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfUser xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<User Name="Rostyslav" UserMail="sample@email.com" Password="123" Age="24" UserRole="Administrator" />
  
<User Name="SomeAnotherGuy" UserMail="sample2@email.com" Password="qwerty" Age="42" UserRole="RegularUser" />

</ArrayOfUser>

Standard .NET class - Dataset also supports xml serialization. In one of my projects I had to get some data (without a strict structure) from one database and store these result data in another one. I loaded all data into Dataset object and just serialized to xml and saved it.

Summary

I think Xml serialization is a nice .NET feature and it is really easy to use and fast to implement. And you don’t have to parse manually XmlDocument anymore. Your code will be more elegant and readable.
Yes, using XmlSerialization is a bad idea when you try to use it with a huge amount of data, it will load all data in the memory, but in the most common cases it is justified.

No comments: