2010-07-06 13 views
5

Ich muss einige Daten in Zeichenfolge serialisieren. Die Zeichenfolge wird dann in einer speziellen Spalte SerializeData in DB gespeichert.Serialisierung und Versionierung

Ich habe spezielle Klassen erstellt, die für die Serialisierung verwendet werden.

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

Serialisierung:

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

Deserialisierung:

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

Jetzt möchte ich Versionierung Unterstützung. Was passiert, wenn ich die Klasse SerializableContingentOrder ändere. Ich möchte in der Zukunft neue Felder hinzufügen können.

Muss ich zur DataContract-Serialisierung wechseln? Bitte geben Sie mir einen kurzen Ausschnitt?

+2

Siehe MSDN; 'SoapFormatter' ist offiziell veraltet: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.soap.soapformatter.aspx –

+0

Ich muss ähnliche Frage, aber ein bisschen Erweiterung davon stellen. Die Daten werden sich definitiv ändern. Können wir die Datenstruktur so gestalten, dass sie die nächste Änderung selbst bewältigen kann? –

Antwort

8

I stark Anwalt gegen Speicherung BinaryFormatter oder SoapFormatter Daten in der Datenbank; es ist:

  • spröde
  • nicht Version tolerant
  • nicht plattformunabhängig

BinaryFormatter für die Datenübertragung zwischen .NET-Assemblies OK ist (an einem Stoß), aber ich würde mehr empfehlen vorhersagbarer Serializer. DataContractSerializer ist eine Option (wie JSON oder XmlSerializer), aber ich würde nichtNetDataContractSerializer aus den gleichen Gründen oben verwenden. I würde versucht sein, protobuf-net zu verwenden, da das effiziente binäre in einem bekannten effizienten Format ist, plattformunabhängig und versionstolerant!

Zum Beispiel:

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

Serialisierung:

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

Deserialisierung:

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

1) Was ist Serializer.Serialize()? Welcher Namespace/Assemply gehört dazu? 2) Vielen Dank für die umfassende Antwort, aber wie meinst du das? "BinaryFormatter oder SoapFormatter ist spröde"? Bitte erweitern Sie ein bisschen –

+2

Sollten Sie sich nicht dagegen aussprechen, statt * nicht * zu speichern? :) Versteh das nicht falsch, Englisch ist nicht meine Muttersprache, daher die Frage. –

+0

@Captain Comic - 'Serializer' ist (pro meiner Antwort) protobuf-net. Re "nicht speichern", es ist korrekt wie geschrieben. ** Ich ** empfehle 'BinaryFormatter' nicht für Speicherzwecke. Re spröde: http://marcgravell.blogspot.com/2009/03/obfuscation-serialization-and.html –

3

Seit .NET 2.0 haben Sie Unterstützung für Version Tolerante Serialisierung, wenn Sie BinaryFormatter verwenden. Die SoapFormatter unterstützt auch einige versionstolerante Funktionen, aber nicht alle, die von BinaryFormatter unterstützt werden, genauer gesagt, die Toleranz von Fremddaten wird nicht unterstützt.

Für weitere Informationen sollten Sie überprüfen:

Version Tolerant Serialization

+1

Nach meiner Erfahrung ist die 'binaryFormatter' "versionstolerante Serialisierung" einfach * nicht *. –

+0

@Marc Gravell, ich nehme dein Wort dafür, aber könnten Sie die spezifischen Probleme, mit denen Sie konfrontiert waren, näher erläutern? –

+0

Stimmen Sie mit Marc überein, VTS ermöglicht einige Änderungen im Code, wie das Hinzufügen eines optionalen Feldes, aber es ist sehr schwierig, sicher zu sein, dass alle nachfolgenden Änderungen "VTS-kompatibel" sind. – VladV

1

Der einfachste Weg, um neue Felder mit den OptionalFieldAttribute zu dekorieren ist. Es ist nicht perfekt, aber es könnte in Ihrem Fall tun.

+0

OptionalField funktioniert nicht für Datenelemente vom Typ 'struct', wie 'Guid'. "Wenn eine Klasse ein Strukturfeld hat, funktioniert das OptionalFieldAttribute nicht mehr." Lesen Sie hier: http://bytes.com/topic/net/answers/850545-optionalfieldattribute-causing-augumentnullexception-deseria – Nayan

5

Sie haben zwei Möglichkeiten, wenn Sie Versionierung unterstützen wollen. Verwenden Sie DataContracts oder verwenden Sie die versionstolerante Serialisierung. Beide sind gültig.

DataContacts übernimmt das automatische Hinzufügen und Entfernen von Feldern. Weitere Informationen finden Sie unter Data Contact Versioning und Best Practices: Data Contract Versioning.

Datacontact Beispiel

[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 Beispiel

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

} 

Mehr Informationen über Version Tolerant Serialization. Beachten Sie besonders die Best Practices am Ende der Seite.

Hinweis, DataContracts wurden in .NET 3.5 eingeführt, daher haben Sie diese Option möglicherweise nicht, wenn Sie .NET 2.0 als Ziel verwenden müssen.

HTH,

+1

OptionalField funktioniert nicht auf 'Struktur' Typ Daten Mitglieder, wie 'Guid'. "Wenn eine Klasse ein Strukturfeld hat, funktioniert das OptionalFieldAttribute nicht mehr." Lesen Sie hier: http://bytes.com/topic/net/answers/850545-optionalfieldattribute-causing-augumentnullexception-deseria – Nayan

+0

Danke @Nayan, ich wusste das nicht. Eine mögliche Lösung/Abhilfe hierfür wäre, die Struktur mit 'Nullable ' zu umbrechen. – Dennis