Condividi tramite


Procedure consigliate: Controllo delle versioni del contratto dati

Questo argomento elenca le procedure consigliate per la creazione di contratti dati che possono evolversi facilmente nel tempo. Per altre informazioni sui contratti dati, vedere gli argomenti in Uso dei contratti dati.

Nota sulla convalida dello schema

Nel discutere del controllo delle versioni del contratto dati, è importante notare che lo schema del contratto dati esportato da Windows Communication Foundation (WCF) non dispone di alcun supporto per il controllo delle versioni, oltre al fatto che gli elementi sono contrassegnati come facoltativi per impostazione predefinita.

Ciò significa che anche lo scenario di controllo delle versioni più comune, ad esempio l'aggiunta di un nuovo membro dati, non può essere implementato in modo trasparente per quanto riguarda uno schema specifico. Le versioni più recenti di un contratto dati (con un nuovo membro dati, ad esempio) non vengono convalidate usando lo schema precedente.

Esistono tuttavia molti scenari in cui non è necessaria una rigorosa conformità dello schema. Molte piattaforme di servizi Web, inclusi i servizi Web WCF e XML creati con ASP.NET, non eseguono la convalida dello schema per impostazione predefinita e pertanto tollerano elementi aggiuntivi non descritti dallo schema. Quando si lavora con tali piattaforme, molti scenari di controllo delle versioni sono più facili da implementare.

Esistono quindi due set di linee guida per il controllo delle versioni del contratto dati: un set per gli scenari in cui la validità rigorosa dello schema è importante e un'altra impostata per gli scenari in caso contrario.

Controllo delle versioni quando è necessaria la convalida dello schema

Se è richiesta una validità rigorosa dello schema in tutte le direzioni (nuovi-a-vecchi e vecchi-a-nuovi), i contratti dati devono essere considerati non modificabili. Se è necessario il controllo delle versioni, deve essere creato un nuovo contratto dati con un nome o uno spazio dei nomi diverso e il contratto di servizio che usa il tipo di dati deve essere sottoposto a controllo delle versioni di conseguenza.

Ad esempio, un contratto di servizio di elaborazione degli ordini di acquisto denominato PoProcessing con un'operazione PostPurchaseOrder accetta un parametro conforme a un PurchaseOrder contratto dati. Se il PurchaseOrder contratto deve cambiare, è necessario creare un nuovo contratto dati, PurchaseOrder2ovvero , che include le modifiche. È quindi necessario gestire il controllo delle versioni a livello di contratto di servizio. Ad esempio, creando un'operazione PostPurchaseOrder2 che accetta il PurchaseOrder2 parametro o creando un PoProcessing2 contratto di servizio in cui l'operazione PostPurchaseOrder accetta un PurchaseOrder2 contratto dati.

Si noti che le modifiche apportate ai contratti dati a cui fanno riferimento altri contratti dati si estendono anche al livello del modello di servizio. Nello scenario precedente, ad esempio, il PurchaseOrder contratto dati non deve essere modificato. Tuttavia, contiene un membro dati di un contratto dati Customer, che a sua volta contiene un membro dati del contratto dati Address, che deve essere modificato. In tal caso, è necessario creare un Address2 contratto dati con le modifiche necessarie, un Customer2 contratto dati contenente il Address2 membro dati e un PurchaseOrder2 contratto dati che contiene un Customer2 membro dati. Come nel caso precedente, anche il contratto di servizio deve essere sottoposto a controllo delle versioni.

Anche se in questi esempi i nomi vengono modificati (aggiungendo un "2"), è consigliabile modificare gli spazi dei nomi anziché i nomi aggiungendo nuovi spazi dei nomi con un numero di versione o una data. Ad esempio, il http://schemas.contoso.com/2005/05/21/PurchaseOrder contratto dei dati verrà modificato nel http://schemas.contoso.com/2005/10/14/PurchaseOrder contratto dei dati.

Per altre informazioni, vedere Procedure consigliate: Controllo delle versioni del servizio.

Occasionalmente, è necessario garantire una rigorosa conformità dello schema per i messaggi inviati dalla tua applicazione, poiché non è possibile affidarsi ai messaggi in arrivo per essere strettamente conformi allo schema. In questo caso, esiste un pericolo che un messaggio in arrivo possa contenere dati estranei. I valori estranei vengono archiviati e restituiti da WCF e pertanto vengono inviati messaggi non validi per lo schema. Per evitare questo problema, la funzionalità di round trip deve essere disattivata. Esistono due modi per eseguire questa operazione.

Per ulteriori informazioni sul round-tripping, vedere Forward-Compatible Contratti di dati.

Controllo delle versioni quando la convalida dello schema non è necessaria

Raramente è necessaria una rigorosa conformità dello schema. Molte piattaforme tollerano elementi aggiuntivi non descritti da uno schema. Purché questo sia tollerato, è possibile usare il set completo di funzionalità descritte in Data Contract Versioning e Forward-Compatible Data Contracts. Sono consigliate le linee guida seguenti.

Alcune delle linee guida devono essere seguite esattamente per inviare nuove versioni di un tipo in cui è prevista una versione precedente o inviare una vecchia in cui è previsto quello nuovo. Altre linee guida non sono strettamente necessarie, ma sono elencate qui perché potrebbero essere interessate dal futuro del controllo delle versioni dello schema.

  1. Non tentare di versionare i contratti di dati tramite l'ereditarietà dei tipi. Per creare versioni successive, modifica il contratto dei dati su un tipo esistente o crea un nuovo tipo distinto.

  2. L'uso dell'ereditarietà insieme ai contratti dati è consentito, a condizione che l'ereditarietà non venga usata come meccanismo di controllo delle versioni e che vengano seguite determinate regole. Se un tipo deriva da un determinato tipo di base, non farlo derivare da un tipo di base diverso in una versione futura (a meno che non abbia lo stesso contratto dati). Esiste un'eccezione a questo: è possibile inserire un tipo nella gerarchia tra un tipo di contratto dati e il relativo tipo di base, ma solo se non contiene membri dati con gli stessi nomi di altri membri in qualsiasi versione possibile degli altri tipi nella gerarchia. In generale, l'uso di membri dati con gli stessi nomi a livelli diversi della stessa gerarchia di ereditarietà può causare gravi problemi di controllo delle versioni e deve essere evitato.

  3. A partire dalla prima versione di un contratto dati, implementare IExtensibleDataObject sempre per abilitare il round trip. Per altre informazioni, vedere Forward-Compatible Contratti dati. Se è stata rilasciata una o più versioni di un tipo senza implementare questa interfaccia, implementarla nella versione successiva del tipo.

  4. Nelle versioni successive, non modificare il nome o lo spazio dei nomi del contratto di dati. Se si modifica il nome o lo spazio dei nomi del tipo sottostante il contratto dati, assicurarsi di mantenere il nome e lo spazio dei nomi del contratto dati usando i meccanismi appropriati, ad esempio la Name proprietà di DataContractAttribute. Per altre informazioni sulla denominazione, vedere Nomi dei contratti dati.

  5. Nelle versioni successive non modificare i nomi di alcun membro dati. Se si modifica il nome del campo, della proprietà o dell'evento sottostante il membro dati, utilizzare la Name proprietà di DataMemberAttribute per mantenere il nome del membro dati esistente.

  6. Nelle versioni successive, non modificare il tipo di alcun campo, proprietà o evento che costituisce un membro dati, in modo da non alterare il contratto dati risultante per quel membro dati. Tenere presente che i tipi di interfaccia sono equivalenti a Object per determinare il contratto dati previsto.

  7. Nelle versioni successive non modificare l'ordine dei membri dati esistenti modificando la Order proprietà dell'attributo DataMemberAttribute .

  8. Nelle versioni successive è possibile aggiungere nuovi membri dati. Devono sempre seguire queste regole:

    1. La IsRequired proprietà deve sempre essere lasciata al valore predefinito di false.

    2. Se un valore predefinito pari null a o zero per il membro non è accettabile, è necessario specificare un metodo di callback utilizzando OnDeserializingAttribute per fornire un valore predefinito ragionevole nel caso in cui il membro non sia presente nel flusso in ingresso. Per maggiori informazioni sul richiamo, vedere Version-Tolerant Richiami di serializzazione.

    3. La DataMemberAttribute.Order proprietà deve essere utilizzata per assicurarsi che tutti i membri dati appena aggiunti vengano visualizzati dopo i membri dati esistenti. Il modo consigliato per eseguire questa operazione è il seguente: nessuno dei membri dati nella prima versione del contratto dati deve avere la proprietà Order impostata. Tutti i membri dati aggiunti nella versione 2 del contratto dati devono avere la proprietà Order impostata su 2. Tutti i membri dati aggiunti nella versione 3 del contratto dati devono avere il loro Order settato su 3 e così via. È consentito impostare più membri dati sullo stesso Order numero.

  9. Non rimuovere i membri di dati nelle versioni successive, anche se la proprietà IsRequired è stata lasciata al valore predefinito di false nelle versioni precedenti.

  10. Non modificare la proprietà IsRequired su alcun membro dati esistente da una versione all'altra.

  11. Per i membri dati obbligatori (dove IsRequired è true), non modificare la EmitDefaultValue proprietà da versione a versione.

  12. Non tentare di creare gerarchie di controllo delle versioni con rami. Ciò significa che deve essere sempre presente un percorso in almeno una direzione da qualsiasi versione a qualsiasi altra versione usando solo le modifiche consentite da queste linee guida.

    Ad esempio, se la versione 1 di un contratto dati Persona contiene solo il membro dati Nome, non è consigliabile creare la versione 2a del contratto aggiungendo solo il membro Età e la versione 2b aggiungendo solo il membro Indirizzo. Il passaggio da 2a a 2b implicherebbe la rimozione dell'età e l'aggiunta dell'indirizzo; nella direzione opposta comporterebbe la rimozione dell'indirizzo e l'aggiunta dell'età. La rimozione dei membri non è consentita da queste linee guida.

  13. In genere non è consigliabile creare nuovi sottotipi di tipi di contratto dati esistenti in una nuova versione dell'applicazione. Analogamente, non è consigliabile creare nuovi contratti dati usati al posto dei membri dati dichiarati come Object o come tipi di interfaccia. La creazione di queste nuove classi è consentita solo quando si sa che è possibile aggiungere i nuovi tipi all'elenco dei tipi noti di tutte le istanze dell'applicazione precedente. Nella versione 1 della tua applicazione, ad esempio, potrebbe essere presente il tipo di contratto di dati LibraryItem con i sottotipi del contratto di dati Book e Newspaper. LibraryItem avrà quindi un elenco di tipi noti che contiene Book e Newspaper. Si supponga di aggiungere ora un tipo Magazine nella versione 2, che è un sottotipo di LibraryItem. Se si invia un'istanza di Magazine dalla versione 2 alla versione 1, il contratto dati Magazine non viene trovato nell'elenco dei tipi noti e viene generata un'eccezione.

  14. Non è consigliabile aggiungere o rimuovere membri di enumerazione tra le versioni. È inoltre consigliabile non rinominare i membri dell'enumerazione, a meno che non si usi la proprietà Name nell'attributo EnumMemberAttribute per mantenere i nomi nel modello del contratto dati lo stesso.

  15. Le raccolte sono intercambiabili nel modello di contratto dati, come descritto in Tipi di raccolta in Contratti dati. Ciò consente un elevato grado di flessibilità. Tuttavia, assicurarsi di non modificare inavvertitamente un tipo di raccolta in modo non intercambiabile da versione a versione. Ad esempio, non cambiare da una raccolta non personalizzata (ovvero senza l'attributo CollectionDataContractAttribute) a una raccolta personalizzata o da una raccolta personalizzata a una raccolta non personalizzata. Inoltre, non modificare le proprietà del CollectionDataContractAttribute da una versione all'altra. L'unica modifica consentita consiste nell'aggiungere una proprietà Name o Namespace se il nome o lo spazio dei nomi del tipo di raccolta sottostante è stato modificato ed è necessario impostarne il nome e lo spazio dei nomi del contratto dati come in una versione precedente.

Alcune delle linee guida elencate qui possono essere ignorate in modo sicuro quando si applicano circostanze speciali. Assicurarsi di comprendere appieno i meccanismi di serializzazione, deserializzazione e schema coinvolti prima di deviare dalle linee guida.

Vedere anche