Versioning Tolerance Serialization in .NET Framework 2.0

This article is based on .NET Framework 2.0 beta 1. This version of .NET Framework has new features called VTS (Versioning Tolerance Serialization). Before discussing this, allow me to define Serialization. Serialization is the process of saving or persisting the object state in to persistence. By using the Deserialization process, you can restore the object state back to where it was before Serialization. This process cycle is called Serialization.

A good example for the Serialization process is the Windows Paint application. You can use the Aaint application to draw any picture, after which, when you want to save this picture, the Paint application uses the serialization process to save the image to file as bytes. Later, if you want to open the saved image file, the Paint application uses the Deserialization process to restore the image.

In .NET Framework the System.Runtime.Serialization namespace provides Serialization-related classes. .NET Framework 1.1 provides two types of serialization formatters, namely Binary and SOAP. You can use SOAP formatters to persist the object state as a SOAP document, simply stored in XML format. Also, just by using the Attribute [Serializable], CLR can serialize the object.

Now, look at what VTS (Versioning Tolerance Serialization) is. Assume that you have created a class called profile. This class contains the following fields:

public class Profile
{
   private string name;
   private string emailAddress;
   private string phone;
   private string country;
}

and are serialized in binary format. Now, version the class defined above to be 1.0. Now you have added a few new fields, called cellPhone and title to that exisiting class, and called it Verison 2.0. The new version of the class looks like this:

public class Profile
   {
      private string name;
      private string emailAddress;
      private string phone;
      private string country;
      private string cellPhone;
      private string title;

  }

Now, if you try to deserialize the old class that is verison 1.0 by using the new class, an exception will be thrown because of a versioning problem. The new class has extra fields called cellphone and title. You can solve this problem now with .NET framework 2.0 by using the new OptionalFieldAttribute (added to System.Runtime.Serialization namespace in .NET 2.0).

Serializing the Profile Class 1.0

You can serialize the Profile class into binary format. For that, you need to import the following namepsace.

// specifying Binary formater.
using System.Runtime.Serialization.Formatters.Binary;

// for opening and creating files.
using System.IO;
// to access all Serilization related classes
using System.Runtime.Serialization ;


using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters;
using System.IO;
using System.Runtime.Serialization ;
namespace ConsoleApplication1
{
   [Serializable]
   public class Profile
   {
      private string name;
      private string emailAddress;
      private string phone;
      private string country;


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

      public string EmailAddress
      {
         get
         {
            return emailAddress;
         }
         set
         {
            emailAddress = value;
         }
      }

      public string Phone
      {
         get
         {
            return phone;
         }
         set
         {
            phone = value;
         }
      }

      public string Country
      {
         get
         {
            return country;
         }

         set
         {
            country = value;
         }
      }

   }
   class Program
   {
      static void Main(string[] args)
      {

         Profile profileobj = new Profile();
         profileobj.Name = "BABA";
         profileobj.EmailAddress = "BABA@Universe.com";
         profileobj.Phone = "9727173364";
         profileobj.Country = "India";

         FileStream fs = new FileStream(@"C:\SavetoBinary",
                                        FileMode.Create);
         BinaryFormatter bfor = new BinaryFormatter();
         bfor.Serialize(fs, profileobj);
         fs.Close();

      }
   }
}

The above program will serialize the Profile object to binary format. Now, deserialize the Profile class version 1.0 with new Version 2.0; then, you will get a exception saying the following:

“Member “cellPhone” in class “ConsoleApplication1.Profile” is not present in the serialized stream and is not marked with System.Runtime.Serialization.OptionalFieldAttribute”.

because there will be a versioning conflict. To solve this problem, you have to use versioning tolerance serailization (VTS). As I mentioned before, this could be done with the OptionalFieldAttribute. With the use of the OptionalFieldAttribute, the new profile class should look like this:

namespace ConsoleApplication1
{
   [Serializable]
   public class Profile
   {
      private string name;
      private string emailAddress;
      private string phone;
      private string country;
      [OptionalField(VersionAdded=2)]
      private string cellPhone;
      [OptionalField(VersionAdded = 2)]
      private string title;

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

      public string EmailAddress
      {
         get
         {
            return emailAddress;
         }
         set
         {
            emailAddress = value;
         }
      }

      public string Phone
      {
         get
         {
            return phone;
         }
         set
         {
            phone = value;
         }
      }

      public string Country
      {
         get
         {
            return country;
         }

         set
         {
            country = value;
         }
      }

      public string CellPhone
      {
         get
         {
            return cellPhone;
         }

         set
         {
            cellPhone = value;
         }
      }

      public string Title
      {
         get
         {
            return title ;
         }

         set
         {
            title = value;
         }
      }

   }
   class Program
   {
      static void Main(string[] args)
      {
         try
         {
            BinaryFormatter soapF = new BinaryFormatter();
            FileStream fs1 = new FileStream(@"C:\SavetoBinary",
                                           FileMode.Open);
            Profile ab1 = (Profile)soapF.Deserialize(fs1);
            Console.WriteLine("De-Serialization is Sucess");
         }
         catch (Exception ex)
         {
            Console.WriteLine(ex.Message);
         }


      }
   }
}

As you can see in the code above, the OptionalFieldAttribute is added to the new field, not to the property. After adding this Optional Filed Attribute, try deserializing the Profile class 1.0 against 2.0 without throwing an exception; it will be able to deserialize the Profile class.

The advantage of Versioning Tolerance serialization is this: Suppose you developed a software application that can be used to draw or design the CAR based on the given input parameters and be able to serialize or save to a file as a binary Image format. Now, after two years, you release a new version of same software, but this version will serialize the designed image with a few new attributes. If you had used VTS, you still could open or de-serialize the old version of the CAR design; it could open it with a new version of this software.

Apart from the OptionalFieldAttribute .NET Framework 2.0, VTS provides four more attributes for serialization. They are:

  • OnDeserializing—This event happens before deserialization
  • OnDeserialized—This event happens after deserialization
  • OnSerializing—This event happens before serialization
  • OnSerialized—This even happens after serialization. By using these new attributes, you can do some logic before and after serialization or when you do the deserialization.

You can use them to mark the methods that would be executed during the serialization and deserialization of the class.

Now, see how you can use the above events-based Serialization attributes. Here, I am going to use these Attributes to set default values before and after deserialization.

[OnDeserializing]
void OnDeserializing(StreamingContext context)
{
   CellPhone = "4170000000";
}


[OnDeserialized]
void OnDeserializedProfile(StreamingContext context)
{
   title  = "Spiritual Leader";
}

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read