Serialization and versioning

半城伤御伤魂 提交于 2019-12-09 13:32:10

问题


I need to serialize some data to string. The string is then stored in DB in a special column SerializeData.

I have created special classes that are used for serialization.

[Serializable]
public class SerializableContingentOrder
{
    public Guid SomeGuidData { get; set; }
    public decimal SomeDecimalData { get; set; }
    public MyEnumerationType1 EnumData1 { get; set; }
}

Serialization:

protected override string Serialize()
{
    SerializableContingentOrder sco = new SerializableContingentOrder(this);

    MemoryStream ms = new MemoryStream();
    SoapFormatter sf = new SoapFormatter();
    sf.Serialize(ms, sco);
    string data = Convert.ToBase64String(ms.ToArray());
    ms.Close();
    return data;
}

Deserialization:

protected override bool Deserialize(string data)
{
    MemoryStream ms = new MemoryStream(Convert.FromBase64String(data).ToArray());
    SoapFormatter sf = new SoapFormatter();

    SerializableContingentOrder sco = sf.Deserialize(ms) as SerializableContingentOrder;
    ms.Close();
    return true;
}

Now I want to have versioning support. What happens if I change SerializableContingentOrder class. I want to be able to add new fields in the future.

Do I have to switch to DataContract serialization? Please give me short snippet?


回答1:


I strongly advocate against storing BinaryFormatter or SoapFormatter data in the database; it is:

  • brittle
  • not version tolerant
  • not platform independent

BinaryFormatter is OK for data transfer between .NET assemblies (at a push), but I would recommend a more predictable serializer. DataContractSerializer is an option (as is JSON or XmlSerializer), but I would not use NetDataContractSerializer for all the same reasons above. I would be tempted to use protobuf-net, since that is efficient binary in a known efficient format, platform independent and version tolerant!

For example:

[DataContract]
public class SerializableContingentOrder
{
    [DataMember(Order=1)] public Guid SomeGuidData { get; set; }
    [DataMember(Order=2)] public decimal SomeDecimalData { get; set; }
    [DataMember(Order=3)] public MyEnumerationType1 EnumData1 { get; set; }
}

Serialization:

protected override string Serialize()
{
    SerializableContingentOrder sco = new SerializableContingentOrder(this);   
    using(MemoryStream ms = new MemoryStream()) {
        Serializer.Serialize(ms, sco);
        return Convert.ToBase64String(ms.ToArray());
    }
}

Deserialization:

protected override bool Deserialize(string data)
{
    using(MemoryStream ms = new MemoryStream(Convert.FromBase64String(data)) {
        SerializableContingentOrder sco =
               Serializer.Deserialize<SerializableContingentOrder>(ms)
    }
    return true;
}



回答2:


You have two options if you want to support versioning. Use DataContracts or use Version Tolerant Serialization. Both are valid.

DataContacts handle the addition and removal of fields automatically. See Data Contact Versioning and Best Practices: Data Contract Versioning for more information.

DataContact Example

[DataContract]
public class ContingentOrder
{
    [DataMember(Order=1)]
    public Guid TriggerDealAssetID;

    [DataMember(Order=2)]
    public decimal TriggerPrice;

    [DataMember(Order=3)]
    public TriggerPriceTypes TriggerPriceType;

    [DataMember(Order=4)]
    public PriceTriggeringConditions PriceTriggeringCondition;

}

Version Tolerant Serialization Example

// Version 1
[Serializable]
public class SerializableContingentOrder
{
    public Guid TriggerDealAssetID;
    public decimal TriggerPrice;
    public TriggerPriceTypes TriggerPriceType;
    // Omitted PriceTriggeringCondition as an example
}

// Version 2 
[Serializable]
public class SerializableContingentOrder
{
    public Guid TriggerDealAssetID;
    public decimal TriggerPrice;
    public TriggerPriceTypes TriggerPriceType;

    [OptionalField(VersionAdded = 2)]
    public PriceTriggeringConditions PriceTriggeringCondition;

    [OnDeserializing]
    void SetCountryRegionDefault (StreamingContext sc)
    {
        PriceTriggeringCondition = /* DEFAULT VALUE */;
    }

}

More information on Version Tolerant Serialization (the link was broken). Especially take note of the best-practices at the bottom of the page.

Note, DataContracts were introduced in .NET 3.5 so you may not have that option if you need to target .NET 2.0.

HTH,




回答3:


Since .NET 2.0 you have Version Tolerant Serialization support if you use BinaryFormatter. The SoapFormatter also supports some version tolerant features but not all the ones supported by the BinaryFormatter, more specifically extraneous data tolerance is not supported.

For more information you should check:

Version Tolerant Serialization




回答4:


The simplest way is to decorate new fields with the OptionalFieldAttribute. It's not perfect but it might do in your case.



来源:https://stackoverflow.com/questions/3185294/serialization-and-versioning

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!