2010-07-06 3 views
5

Мне нужно сериализовать некоторые данные в строку. Строка затем сохраняется в БД в специальном столбце SerializeData.Сериализация и управление версиями

Я создал специальные классы, которые используются для сериализации.

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

Сериализация:

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; 
} 

Десериализация:

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; 
} 

Теперь я хочу, чтобы иметь поддержку версионности. Что произойдет, если я изменю класс SerializableContingentOrder. Я хочу иметь возможность добавлять новые поля в будущем.

Должен ли я переключиться на сериализацию DataContract? Пожалуйста, дайте мне короткий фрагмент?

+2

См. MSDN; «SoapFormatter» официально устарел: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.soap.soapformatter.aspx –

+0

Мне нужно задать аналогичный вопрос, но немного его расширить. Данные будут меняться определенно, можем ли мы создать структуру данных для самостоятельной обработки следующего изменения? –

ответ

8

Я сильно адвокат против хранения BinaryFormatter или SoapFormatter данных в базе данных; это:

  • хрупкие
  • не версия терпима
  • не зависит от платформы

BinaryFormatter ОК для передачи данных между сборками .NET (при нажатии), но я бы рекомендовал более предсказуемый сериализатор. DataContractSerializer является опцией (как есть JSON или XmlSerializer), но I не будет использовать NetDataContractSerializer по всем тем же причинам выше. I : будет искушать использование protobuf-net, так как это эффективный двоичный файл в известном эффективном формате, независимый от платформы и толерантный к версии!

Например:

[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; } 
} 

Сериализация:

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

Десериализация:

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

1) Что такое Serializer.Serialize()? Какое пространство имен/assemply оно принадлежит? 2) Благодарим вас за такой исчерпывающий ответ, но как вы это понимаете? «BinaryFormatter или SoapFormatter - хрупкий»? Plese развернуть немного –

+2

Разве вы не должны защищать от хранения вместо * not * хранения? :) Не поймите это неправильно, английский не мой родной язык, следовательно, вопрос. –

+0

@Captain Comic - 'Serializer' (за мой ответ) protobuf-net. Re «не хранить», это правильно, как написано. Я ** ** не рекомендую 'BinaryFormatter' для хранения. Re хрупкий: http://marcgravell.blogspot.com/2009/03/obfuscation-serialization-and.html –

3

С .NET 2.0 у вас есть поддержка версии Tolerant Serialization, если вы используете BinaryFormatter. SoapFormatter также поддерживает некоторые толерантные для версии функции, но не все поддерживаемые BinaryFormatter, более конкретный посторонний перенос данных не поддерживается.

Для получения дополнительной информации вы должны проверить:

Version Tolerant Serialization

+1

По моему опыту, версия «BinaryFormatter» с толерантной сериализацией «просто *» не *. –

+0

@Marc Gravell, я возьму ваше слово за это, но не могли бы вы рассказать о конкретных проблемах, с которыми вы столкнулись? –

+0

Согласитесь с Marc, VTS допускает некоторые изменения в коде, например добавление необязательного поля, но очень сложно убедиться, что все последующие изменения будут «совместимы с VTS». – VladV

1

Самый простой способ украсить новые поля с OptionalFieldAttribute. Это не идеально, но это может быть в вашем случае.

+0

НеобязательныйField не работает с элементами данных типа 'struct', например 'Guid'. «когда класс имеет поле структуры, OptionalFieldAttribute перестанет работать». Читайте здесь: http://bytes.com/topic/net/answers/850545-optionalfieldattribute-causing-augumentnullexception-deseria – Nayan

5

У вас есть два варианта, если вы хотите поддерживать управление версиями. Используйте DataContracts или используйте версию Tolerant Serialization. Оба действительны.

DataContact обрабатывает добавление и удаление полей автоматически. См. Data Contact Versioning и Best Practices: Data Contract Versioning для получения дополнительной информации.

DataContact Пример

[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 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 */; 
    } 

} 

Более подробную информацию о Version Tolerant Serialization. Особенно обратите внимание на лучшие практики в нижней части страницы.

Note, DataContracts были введены в .NET 3.5, поэтому у вас может не быть этого параметра, если вам нужно настроить .NET 2.0.

HTH,

+1

Необязательный Field не работает с элементами данных типа «struct», например «Guid». «когда класс имеет поле структуры, OptionalFieldAttribute перестанет работать». Читайте здесь: http://bytes.com/topic/net/answers/850545-optionalfieldattribute-causing-augumentnullexception-deseria – Nayan

+0

Спасибо @Nayan, я этого не знал. Одним из возможных решений/обходных путей для этого было бы обернуть структуру, используя «Nullable ». – Dennis