XML Serilization Tutorial

Introduction

Many people ask that how XML serialization work, how can we serialize our data to permanent storage. My objective is to save and load data in XML and avoid the complexity of DOM (Document Object Model). Also I want to drive a generalized mechanism which can be used in multiple projects without modification.
 
In this tutorial I am considering a case of Simple Invoice System. I will share different tricks through we can control how our data is serialized into XML.

Code
You can download the code from this location.

Overview of Application

I have created a simple GUI through which we can enter information related to invoice. Keep in mind that to keep things simple, I have not added any kind of validation in my code so you have to enter valid values by yourself. Here is the snapshot of the application :-


Serialization Implementation
I have implemented two methods in SerlizationExtension class which are responsible for serialization and de-serialization of data. Both methods are implemented as extension method, so they are available for every object and they also take an additional parameter for file name. Here is the code for your quick reference:-

/// <summary>
/// Summary description for SerlizationExtension
/// </summary>
public static class SerlizationExtension
{

    /// <summary>
    /// Serializes the specified object.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="Object">The object.</param>
    /// <param name="fileName">Name of the file.</param>
    public static void Serialize<T>(this T Object, string fileName)
    {
        string filePath = HttpContext.Current.Server.MapPath(".") + "\\" + fileName;
        XmlSerializer s = new XmlSerializer(Object.GetType());
        using (StreamWriter writer = new StreamWriter(filePath))
        {
            s.Serialize(writer, Object);
            writer.Close();
        }
    }

    /// <summary>
    /// Deserializes the specified object.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="Object">The object.</param>
    /// <param name="fileName">Name of the file.</param>
    /// <returns></returns>
    public static T Deserialize<T>(this T Object, string fileName)
    {
        string filePath = HttpContext.Current.Server.MapPath(".") + "\\" + fileName;
        XmlSerializer s = new XmlSerializer(typeof(T));
        using (StreamReader sr = new StreamReader(filePath))
        {
            object obj = s.Deserialize(sr);
            return (T)obj;
        }
    }
}

In case you want to implement serialization in your code then you have to add above class in your project as well. Once you have added above class in your solution, you can simply call Serialize/DeSerialize. Also make sure that you add [Serializable] attribute on your class. Here is a sample that how you can call both methods:-

    /// <summary>
    /// Loads the invoice.
    /// </summary>
    private void LoadInvoice()
    {
        Invoice = Invoice.Deserialize("test.xml");
        BindInvoice();
    }

    /// <summary>
    /// Saves the invoice.
    /// </summary>
    private void SaveInvoice()
    {
        Invoice.Serialize("test.xml");
    }

Scenario 1
Here is the copy of InvoiceMaster and InvoiceDetail class:-

/// <summary>
/// Summary description for InvoiceMaster
/// </summary>
[Serializable]
public class InvoiceMaster
{
    public int InvoiceID { get; set; }
    public string CustomerName { get; set; }
    public DateTime IssueDate { get; set; }

    public List<InvoiceDetail> Childs { get; set; }

    public decimal TotalPrice
    {
        get
        {
            return (from l in Childs select l.SubTotal).Sum();
        }
    }

    public InvoiceMaster()
    {
        Childs = new List<InvoiceDetail>();
    }
}

/// <summary>
/// Summary description for InvoiceDetail
/// </summary>
///
[Serializable]
public class InvoiceDetail
{
    public string ItemName { get; set; }
    public decimal Price { get; set; }
    public int Quantity { get; set; }
    public decimal SubTotal { get { return ((decimal)Quantity) * Price; } }
}

Here is the sample output of test.xml which is generated with above classes:-

<?xml version="1.0" encoding="utf-8"?>
<InvoiceMaster xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <InvoiceID>1</InvoiceID>
  <CustomerName>Zeeshan Umar</CustomerName>
  <IssueDate>2011-01-01T00:00:00</IssueDate>
  <Childs>
    <InvoiceDetail>
      <ItemName>Pepsi 500ml</ItemName>
      <Price>40</Price>
      <Quantity>2</Quantity>
    </InvoiceDetail>
    <InvoiceDetail>
      <ItemName>Marinda 500ml</ItemName>
      <Price>40</Price>
      <Quantity>1</Quantity>
    </InvoiceDetail>
    <InvoiceDetail>
      <ItemName>Dew 500ml</ItemName>
      <Price>40</Price>
      <Quantity>1</Quantity>
    </InvoiceDetail>
  </Childs>
</InvoiceMaster>

Scenario 2
Although XML is generated with simply adding [Serializable] tags. But sometimes we want to serialize properties as attributes in XML rather than element. To do this I have modified my classes little bit. Here is the updated code for my classes:-

/// <summary>
/// Summary description for InvoiceMaster
/// </summary>
[Serializable]
[XmlRoot("Master")]
public class InvoiceMaster
{
    [XmlAttribute("ID")]
    public int InvoiceID { get; set; }

    [XmlAttribute("CustomerName")]
    public string CustomerName { get; set; }

    [XmlAttribute("IssueDate")]
    public DateTime IssueDate { get; set; }

    [XmlArray("Details")]
    public List<InvoiceDetail> Childs { get; set; }

    [XmlIgnore]
    public decimal TotalPrice
    {
        get
        {
            return (from l in Childs select l.SubTotal).Sum();
        }
    }

    public InvoiceMaster()
    {
        Childs = new List<InvoiceDetail>();
    }
}

/// <summary>
/// Summary description for InvoiceDetail
/// </summary>
[Serializable]
public class InvoiceDetail
{
    [XmlAttribute("Name")]
    public string ItemName { get; set; }

    [XmlAttribute("Price")]
    public decimal Price { get; set; }

    [XmlAttribute("Quantity")]
    public int Quantity { get; set; }

    [XmlIgnore]
    public decimal SubTotal { get { return ((decimal)Quantity) * Price; } }
}

Here is the XML generated with above classes:-

<?xml version="1.0" encoding="utf-8"?>
<Master xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ID="0" CustomerName="" IssueDate="0001-01-01T00:00:00">
  <Details>
    <InvoiceDetail Name="Pepsi" Price="1" Quantity="40" />
    <InvoiceDetail Name="Coke" Price="2" Quantity="40" />
    <InvoiceDetail Name="Dew" Price="2" Quantity="40" />
  </Details>
</Master>

As you can see this time XML is quite simple, short and more readable compared with previous scenario. I have added [XmlAttribute()] attribute on the properties which mean that properties will be added as attribute in XML. Also I have specified [XmlIgnore] attribute on those properties which I dont want to serilize. Note that readonly properties can not be serilized and it is better to add [XmlIgnore] attribute on those properties.

Conclusion
We have seen in above samples that how we can take advantage of serialization mechanism provided by .Net. In this tutorial I have tried to keep things as simple as possible so you can understand the basic concepts of XML serialization. Feel free to share your comments. Happy Coding !!!