Implementing ISerializable for version control

Consider the following type of POD class:

public class Price { public decimal OfferPrice { get; set; } }

      

objects from this class are fetched from the server, so let's decorate it with Serializable

[Serializable]
public class Price { public decimal OfferPrice { get; set; } }

      

Now two clients on different machines are retrieving these objects. They won't post prices. They all receive a copy of the price collector.

The class is now being extended with BonusPrice.

[Serializable]
public class Price { 
  public decimal OfferPrice { get; set; } 
  public decimal BonusPrice { get; set; } 
}

      

The new assembly is deployed to the server, to one of the clients, but NOT to the other. So the old versioned client will fail when (de) serializing Price objects.

The client with the old version does not need the BonusPrice field, so it would be nice that it keeps running when there is a version difference. So I am thinking of implementing ISerializable from the beginning, so the first and second versions will look like this:

// version 1.0
[Serializable]
public class Price : ISerializable {
  protected Price(SerializationInfo info, StreamingContext context) {
    OfferPrice = info.GetDecimal("op");
  }

  [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
  public virtual void GetObjectData(SerializationInfo info, StreamingContext context) {
    info.AddValue("op", OfferPrice);
  }
}

// version 2.0
[Serializable]
public class Price : ISerializable {
  protected Price(SerializationInfo info, StreamingContext context) {
    OfferPrice = info.GetDecimal("op");
    BonusPrice = info.GetDecimal("bp");
  }

  [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
  public virtual void GetObjectData(SerializationInfo info, StreamingContext context) {
    info.AddValue("op", OfferPrice);
    info.AddValue("bp", BonusPrice);
  }
}

      

So now that one client is not upgrading to version 2, it will still continue to deserialize only OfferPrice and not crash. When it gets updated at some point, it will automatically use BonusPrice.

My question is, does ISerializable implement a good way of versioning when reading objects? How are these problems usually solved?

+3


source to share


2 answers


You can use OptionalFieldAttribute for version control BinaryFormatter

and SoapFormatter

.

The optionalFieldAttribute has a VersionAdded property . This is not used in version 2.0 of the .NET Framework. However, it is important to set this property correctly to ensure that the type will be compatible with future serialization mechanisms.

The property indicates which version of the type that the given field was added to. It must be incremented by one (starting at 2) every time the type is changed



There are other ways as well, such as Serialization callbacks, SerializationBinder, ISerializable

etc.

Refer to Version Tolerant Serialization for more information.

+2


source


From my point of view, you are trying to mix two versions of the protocols in one contract. In your example this works, but in practice it is often difficult to unify a new protocol, so it is best to leave them separate. In other words, your server must support both versions on its own. Have a look at OData Protocol Versioning



+1


source







All Articles