2011-08-16 16 views
5

Ho una situazione in cui sto serializzando alcuni oggetti .NET utilizzando NetDataContractSerializer e memorizzando l'XML in un database come un modo per ricordare lo stato di questi oggetti all'interno di un'applicazione. Recentemente mi sono imbattuto nella prima situazione in cui alcuni refactoring del codice di proprietà e nomi di tipo hanno portato alla mancata deserializzazione di questi dati XML.Problemi di deserializzazione con NetDataContractSerializer dopo il codice di refactoring

Finora sono arrivati ​​due diversi piani di attacco per come gestire le interruzioni di compatibilità delle versioni come quelle che utilizzano le funzionalità disponibili all'interno di NetDataContractSerializer stesso per controllare la deserializzazione o semplicemente per trasformare l'XML direttamente. Dalla mia sperimentazione e ricerca sembra che si possa deserializzare con un diverso tipo usando un custom SerializationBinder e le modifiche di nome/tipo di proprietà possono essere affrontate sia implementando ISerializable o scrivendo un surrogato di serializzazione implementando ISurrogateSelector e ISerializationSurrogate. Sfortunatamente questo meccanismo preferito non è stato eliminato e, a meno che non possa essere mostrato diversamente, sembra che usare il surrogato tra la versione dei dati serializzati non sia possibile con NetDataContractSerializer e questo è dovuto ad un inspiegabile design decision by Microsoft. Ciò che Microsoft ha suggerito è di usare la stessa serializzazione su entrambi i lati che vanifica completamente lo scopo dell'utilizzo di un surrogato per aiutare nei casi in cui un nome di tipo cambia o viene spostato in uno spazio dei nomi o in un assembly diversi.

Per risolvere il problema, si prega di utilizzare la stessa istanza NetDataContractSerializer o un'altra istanza che viene anche inizializzato con un SurrogateSelector compatibili.

Questa spiegazione è in conflitto con an MSDN article che ha a che fare con l'utilizzo di un raccoglitore personalizzato per sostituire i tipi e gestire altre modifiche nella struttura di serializzazione.

Durante la deserializzazione, il formattatore vede che è stato impostato un legatore. Poiché ogni oggetto sta per essere deserializzato, il formatter chiama il metodo BindToType del bindToType , passandogli il nome dell'assembly e digitando che il formattatore deve deserializzare. . A questo punto, BindToType decide quale tipo deve essere effettivamente costruito e restituisce questo tipo.

Si noti che il tipo originale e il nuovo tipo devono avere lo stesso campo esatto nomi e tipi se il nuovo tipo utilizza la serializzazione semplice tramite l'attributo personalizzabile serializzabile . Tuttavia, la nuova versione del tipo potrebbe implementare l'interfaccia ISerializable e il relativo costruttore speciale verrà chiamato e il tipo può esaminare i valori nell'oggetto SerializationInfo e determinare come deserializzare sé stesso.

Quindi, o ho intenzione di essere in grado di ottenere NetDataContractSerializer lavorare per deserializzare il mio V1 XML nelle mie tipi V2 o ho intenzione di avere per trasformare manualmente il codice XML. Se qualcuno può provare che SerializationInfo di NetDataContractSerializer funziona effettivamente quando si utilizza ISerializable o si utilizzano surrogati di serializzazione che sarebbero eccellenti o almeno fornire una spiegazione migliore di quella fornita da Microsoft, altrimenti probabilmente invierò una nuova domanda per discutere il modo migliore in .NET per trasformare direttamente il vecchio XML.

UPDATE 2011-08-16: Dopo alcuni esperimenti risulta che l'ISerializable e tecnica serializzazione surrogata entrambi funzionano bene se il tipo originale che è stato serializzato attuata ISerializable altrimenti se il tipo appena utilizzarlo [Serializable] attribuiscili sembra che a ogni campo nel grafico degli oggetti manchino alcune preziose informazioni sul tipo sotto forma di attributi aggiuntivi.

Esempio con [Serializable] attributo

<OldClass2 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="1" z:Type="NdcsSurrogateTest.OldClass2" z:Assembly="NdcsSurrogateTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns="http://schemas.datacontract.org/2004/07/NdcsSurrogateTest"> 
    <_stable z:Id="2">Remains the same</_stable> 
    <_x003C_OldProperty_x003E_k__BackingField>23</_x003C_OldProperty_x003E_k__BackingField> 
</OldClass2> 

Esempio attuazione ISerialzable:

<OldClass2 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema" z:Id="1" z:Type="NdcsSurrogateTest.OldClass2" z:Assembly="NdcsSurrogateTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns="http://schemas.datacontract.org/2004/07/NdcsSurrogateTest"> 
    <_stable z:Id="2" z:Type="System.String" z:Assembly="0" xmlns="">Remains the same</_stable> 
    <_x003C_OldProperty_x003E_k__BackingField z:Id="3" z:Type="System.Int32" z:Assembly="0" xmlns="">23</_x003C_OldProperty_x003E_k__BackingField> 
</OldClass2> 

Quando deserializzazione primo esempio usando l'NetDataContractSerializer con un legante personalizzato per modificare il tipo e poi o implementando ISerializable su quel tipo o fornendo un selettore surrogato che designa un surrogato di serializzazione che è basico assolve il ruolo di ISerializalbe, quindi vedrai un SerializationInfo vuoto nel metodo ISerializationSurrogate.SetObjectData. Quando si elabora l'xml nel secondo esempio, SerializationInfo sembra ottenere le informazioni giuste e le cose funzionano come previsto.

La mia conclusione è che l'XML predefinito prodotto da NetDataContractSerializer per i tipi che supportano la serializzazione solo tramite SerializableAttribute non sarà compatibile con la deserializzazione utilizzando tecniche surrogate ISerializable o di serializzazione a causa della mancanza di informazioni sul tipo. Quindi, per rendere l'uso di NetDataContractSerializable più a prova di futuro, è necessario personalizzare la serializzazione per garantire che questo tipo di informazioni sia incluso in XML in modo che la successiva deserializzazione possa essere personalizzata senza la trasformazione manuale dell'XML di origine.

risposta

2

Sì, è necessario disporre di un percorso di migrazione dei dati ben congegnato se si utilizza la serializzazione. La soluzione che hai menzionato è quello che farei personalmente, per includere un controllo nel codice che deserializza. Se viene rilevata una versione precedente, eseguire una piccola trasformazione in modo che corrisponda al nuovo formato e procedere secondo le necessità. Una volta che tutti i dati sono stati trasformati, quel codice può essere reso obsoleto in una versione futura.

+1

Grazie per il suggerimento. Questa sarà la mia opzione di fallback. L'unica cosa di cui sono un po 'preoccupato sono i complicati spazi dei nomi all'interno dell'output di NetDataContractSerializer che sono sicuro che faranno la scrittura divertente di XSLT. Forse può essere una buona ragione con Linq to XML o semplicemente manipolazione di tipo Dom XML. – jpierson

Problemi correlati