2010-07-06 16 views
5

Ho bisogno di serializzare alcuni dati nella stringa. La stringa viene quindi memorizzata in DB in una colonna speciale SerializeData.Serializzazione e controllo delle versioni

Ho creato classi speciali che vengono utilizzate per la serializzazione.

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

serializzazione:

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

deserializzazione:

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

Ora voglio avere delle versioni supporto. Cosa succede se cambio classe SerializableContingentOrder. Voglio poter aggiungere nuovi campi in futuro.

Devo passare alla serializzazione DataContract? Per favore, dammi un breve frammento?

+2

Vedere MSDN; 'SoapFormatter' è ufficialmente obsoleto: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.soap.soapformatter.aspx –

+0

Ho bisogno di fare una domanda simile ma un po 'di estensione. I dati cambieranno definitivamente, possiamo strutturare i dati in modo da gestire autonomamente il prossimo cambiamento? –

risposta

8

ho fortemente avvocato contro memorizzazione BinaryFormatter o SoapFormatter dati nel database; è:

  • fragile
  • non versione tollerante
  • non indipendente dalla piattaforma

BinaryFormatter è ok per il trasferimento dei dati tra assembly .NET (ad una spinta), ma mi sento di raccomandare un più serializzatore prevedibile. DataContractSerializer è un'opzione (come è JSON o XmlSerializer), ma I non utilizzare NetDataContractSerializer per tutti gli stessi motivi sopra. I sarebbe essere tentati di utilizzare protobuf-net, dal momento che è efficiente binario in un formato efficiente noto, indipendente dalla piattaforma e tollerante della versione!

Ad esempio:

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

serializzazione:

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

deserializzazione:

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

1) Che cos'è Serializer.Serialize()? A quale namespace/assemply appartiene? 2) Grazie per la risposta completa, ma come intendete "BinaryFormatter o SoapFormatter è fragile"? Plese espandi un po ' –

+2

Non dovresti difendere la memorizzazione anziché * non * memorizzare? :) Non farlo nel modo sbagliato, l'inglese non è la mia lingua madre, quindi la domanda. –

+0

@Captain Comic - 'Serializer' è (per mia risposta) protobuf-net. Ri "non memorizzare", è corretto come scritto. I ** non ** consiglia 'BinaryFormatter' per scopi di archiviazione. Re fragile: http://marcgravell.blogspot.com/2009/03/obfuscation-serialization-and.html –

3

Dal momento che .NET 2.0 dispone del supporto per la serializzazione della tolleranza di versione se si utilizza BinaryFormatter. Lo SoapFormatter supporta anche alcune funzioni tolleranti la versione, ma non tutte quelle supportate dalla BinaryFormatter, la tolleranza dei dati più specificamente estranea non è supportata.

Per ulteriori informazioni si dovrebbe verificare:

Version Tolerant Serialization

+1

In base alla mia esperienza, la serializzazione tollerante della versione "BinaryFormatter'" semplicemente * non è *. –

+0

@ Marc Gravell, ti prendo in parola, ma potresti approfondire i problemi specifici che hai affrontato? –

+0

D'accordo con Marc, VTS consente alcune modifiche nel codice, come l'aggiunta di un campo opzionale, ma è molto difficile essere sicuri che tutte le modifiche successive saranno "compatibili VTS". – VladV

1

Il modo più semplice è quella di decorare nuovi campi con il OptionalFieldAttribute. Non è perfetto, ma potrebbe farlo nel tuo caso.

+0

OptionalField non funziona su membri di tipo "struct" come "Guid". "quando una classe ha un campo struttura, il OptionalFieldAttribute smetterà di funzionare." Leggi qui: http://bytes.com/topic/net/answers/850545-optionalfieldattribute-causing-augumentnullexception-deseria – Nayan

5

Hai due opzioni se si desidera supportare il controllo delle versioni. Utilizzare DataContracts o utilizzare Serialization Version Tolerant. Entrambi sono validi.

DataContacts gestisce l'aggiunta e la rimozione automatica dei campi. Vedere Data Contact Versioning e Best Practices: Data Contract Versioning per ulteriori informazioni.

Datacontact Esempio

[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 serializzazione Esempio

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

} 

Maggiori informazioni su Version Tolerant Serialization. Soprattutto prendi nota delle migliori pratiche in fondo alla pagina.

Nota: i DataContracts sono stati introdotti in .NET 3.5, pertanto è possibile che non si disponga di tale opzione se è necessario utilizzare .NET 2.0.

HTH,

+1

OptionalField non funziona su membri di tipo "struct", come "Guid". "quando una classe ha un campo struttura, il OptionalFieldAttribute smetterà di funzionare." Leggi qui: http://bytes.com/topic/net/answers/850545-optionalfieldattribute-causing-augumentnullexception-deseria – Nayan

+0

Grazie @Nayan, non lo sapevo. Una soluzione possibile/soluzione per questo sarebbe quello di avvolgere la struttura usando 'Nullable '. – Dennis

Problemi correlati