programming4us
programming4us
ENTERPRISE

Programming .NET Components : Serialization Events (part 3) - Type-Version Tolerance

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019

4. Type-Version Tolerance

In .NET 1.1, there had to be absolute compatibility between the metadata used to serialize a type and the metadata used to deserialize a type. This meant that if your application had clients with the serialized state of your types, your type members' metadata had to be immutable, or you would break those clients.

In .NET 2.0, the formatters acquired some version-tolerance capabilities. The tolerance is with respect to changes in the type metadata, not changes to the assembly version itself. Imagine a class-library vendor that provides a serializable component. The various client applications are responsible for managing the serialization medium (typically a file). Suppose the vendor changes the component definition, by adding a member variable. Such a change does not necessitate a version change, because binary compatibility is maintained. New client applications can serialize the new component properly. However, the serialization information captured by the old applications is now incompatible, and will result in a SerializationException if used in .NET 1.1. The vendor can, of course, increment the assembly version number, but doing so will prevent the old clients from taking advantage of the new functionality. The formatters in .NET 2.0 were redesigned to handle such predicaments.

In the case of removing an unused member variable, the binary formatter will simply ignore the additional information found in the stream. For example, suppose you use this class (but not a struct) definition and serialize it using a binary formatter:

    //Version 1.0
    [Serializable]
    public class MyClass
    {
       public int Number1;
       public int Number2;
    }

Without changing the assembly version, remove one of the member variables:

    //Version 2.0
    [Serializable]
    public class MyClass
    {
       public int Number1;
    }

You can then rebuild, redeploy, and deserialize instances of version 2.0 of MyClass with the serialization information captured using version 1.0 of MyClass.

The real challenge in type-version tolerance is dealing with new members, because the old serialization information does not contain any information about them. By default, the formatters are not tolerant toward the new members and will throw an exception when they encounter them.

.NET 2.0 addresses this problem by providing a field attribute called OptionalField—a simple attribute with a single public property of type int, called VersionAdded:

    [AttributeUsage(AttributeTargets.Field,Inherited = false)]
    public sealed class OptionalFieldAttribute : Attribute
    {
       public int VersionAdded(get;set);
    }

Applying the OptionalField attribute has no effect during serialization, and fields marked with it will be serialized into the stream. This is because OptionalField is meant to be applied on new fields of your type, and it causes the formatters to ignore the new members during deserialization:

    //Version 1.0
    [Serializable]
    public class MyClass
    {
       public int Number1;
    }
    //Version 2.0
    [Serializable]
    public class MyClass
    {
       public int Number1;
    
       [OptionalField]
       public int Number2;
    }

That said, if the new member variable has a good-enough default value, such as the application's default directory or user preferences, you can use values provided by the new clients to synthesize values for the old clients. You will need to provide these values in your handling of the deserializing event. If you do so before deserialization and the stream does contain serialized values, the serialized values are preferable to the synthesized ones, and the deserialization process will override the values you set in the handling of the deserializing event.

Consider, for example, this class version:

    //Version 1.0
    [Serializable]
    public class MyClass
    {
       public int Number1;
    }

Suppose you want to add a new class member called Number2, while using the old serialization information. You need to provide handling to the deserializing event, and in it initialize Number2:

    [Serializable]
    public class MyClass
    {

       public int Number1;
       [OptionalField]
       public int Number2;

       [OnDeserializing]
       void OnDeserializing(StreamingContext context)
       {
          Number2 = 123;
       }
    }

But what if the values you synthesize are somehow dependent on the version of the class in which they are added? You can store version information in the OptionalField attribute, using its VersionAdded member:

    [OptionalField(VersionAdded = 1)]
    public int Number2;

In the deserializing event handler you will need to use reflection to read the value of the VersionAdded field and act accordingly, as shown in Example 3. This example uses the helper method OptionalFieldVersion( ) of the SerializationUtil static helper class. OptionalFieldVersion( ) accepts the type and the member variable name to reflect, returning the value of the VersionAdded field:

    public static string OptionalFieldVersion(Type type,string member);

Example 3. Relying on VersionAdded
[Serializable]
public class MyClass
{
   public int Number1;

   [OptionalField(VersionAdded = 1)]
   public int Number2;


   [OnDeserializing]
   void OnDeserializing(StreamingContext context)
   {
      int versionAdded;
      versionAdded = SerializationUtil.OptionalFieldVersion(typeof(MyClass),
                                                            "Number2");
      if(versionAdded == 1)
         Number2 = 123;
      if(versionAdded == 2)
         Number2 = 456;
   }
}

public static class SerializationUtil
{
   public static int OptionalFieldVersion(Type type,string member)
   {
      Debug.Assert(type.IsSerializable);

      MemberInfo[] members = type.GetMember(member,BindingFlags.Instance |
                                                   BindingFlags.NonPublic|
                                                   BindingFlags.Public   |
                                                   BindingFlags.DeclaredOnly);
      Debug.Assert(members.Length == 1);
      object[] attributes =
    members[0].GetCustomAttributes(typeof(OptionalFieldAttribute),false);
      Debug.Assert(attributes.Length == 1);//Exactly one attribute is expected

      OptionalFieldAttribute attribute;
      attribute = attributes[0] as OptionalFieldAttribute;
      return attribute.VersionAdded;
   }
}

					  

The next version of the serialization infrastructure (a part of Indigo) will provide a formatter that is version-tolerant, as well as support for version-added information for the optional fields.

Other  
 
Top 10
Free Mobile And Desktop Apps For Accessing Restricted Websites
MASERATI QUATTROPORTE; DIESEL : Lure of Italian limos
TOYOTA CAMRY 2; 2.5 : Camry now more comely
KIA SORENTO 2.2CRDi : Fuel-sipping slugger
How To Setup, Password Protect & Encrypt Wireless Internet Connection
Emulate And Run iPad Apps On Windows, Mac OS X & Linux With iPadian
Backup & Restore Game Progress From Any Game With SaveGameProgress
Generate A Facebook Timeline Cover Using A Free App
New App for Women ‘Remix’ Offers Fashion Advice & Style Tips
SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th
- Messages forwarded by Outlook rule go nowhere
- Create and Deploy Windows 7 Image
- How do I check to see if my exchange 2003 is an open relay? (not using a open relay tester tool online, but on the console)
- Creating and using an unencrypted cookie in ASP.NET
- Directories
- Poor Performance on Sharepoint 2010 Server
- SBS 2008 ~ The e-mail alias already exists...
- Public to Private IP - DNS Changes
- Send Email from Winform application
- How to create a .mdb file from ms sql server database.......
programming4us programming4us
programming4us
 
 
programming4us