Procedure consigliate: controllo delle versioni del contratto dati
In questo argomento vengono elencate le procedure consigliate per la creazione di contratti dati che possono essere ulteriormente sviluppate nel tempo. Per ulteriori informazioni sui contratti dati, vedere gli argomenti in Utilizzo di contratti dati.
Note sulla convalida dello schema
Nella valutazione del controllo delle versioni per il contratto dati, è importante notare che lo schema del contratto dati esportato da Windows Communication Foundation (WCF) non supporta il controllo delle versioni se non per il fatto che gli elementi vengono contrassegnati come facoltativi per impostazione predefinita.
Di conseguenza, anche lo scenario di controllo delle versioni più comune, quale l'aggiunta di un nuovo membro dati, non può essere implementato agevolmente rispetto a un schema specificato. Le versioni più recenti di un contratto dati (ad esempio con un nuovo membro dati) non vengono convalidate utilizzando lo schema obsoleto.
Esistono tuttavia molti scenari in cui non è richiesta una totale conformità allo schema. Molte piattaforme dei servizi Web, incluso WCF e i servizi Web XML creati utilizzando ASP.NET, non eseguono la convalida dello schema per impostazione predefinita e pertanto tollerano elementi aggiuntivi che non sono descritti nello schema. Se si utilizzano tali piattaforme, l'implementazione di molti scenari di controllo delle versioni risulta più semplice.
Sono pertanto disponibili due set di linee guida per il controllo delle versioni di un contratto dati: un set per gli scenari in cui la rigorosa validità dello schema è importante e un altro set per gli scenari in cui non lo è.
Controllo delle versioni quando la convalida dello schema è necessaria
Se la rigorosa validità dello schema è necessaria in tutte le direzioni (da nuovo a vecchio e da vecchio a nuovo), i contratti dati devono essere considerati immutabili. Se occorre eseguire il controllo delle versioni, è necessario creare un nuovo contratto dati, con un nome o uno spazio dei nomi diverso e il contratto di servizio che utilizza il tipo di dati deve essere sottoposto al controllo delle versioni.
Ad esempio, un contratto di servizio che elabora un ordine di acquisto denominato PoProcessing
con un'operazione PostPurchaseOrder
accetta un parametro basato su un contratto dati PurchaseOrder
. Se è necessario modificare il contratto PurchaseOrder
, creare un nuovo contratto dati, ovvero PurchaseOrder2
, che includa le modifiche. È quindi necessario gestire il controllo delle versioni a livello del contratto di servizio. Ad esempio, creando un'operazione PostPurchaseOrder2
che accetta il parametro PurchaseOrder2
o creando un contratto di servizio PoProcessing2
in cui l'operazione PostPurchaseOrder
accetta un contratto dati PurchaseOrder2
.
Si noti che se altri contratti dati fanno riferimento alle modifiche apportate ai contratti dati, queste si estenderanno anche a livello del modello di servizio. Ad esempio, si supponga che nello scenario precedente il contratto dati PurchaseOrder
non abbia bisogno di modifiche. Tale contratto 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 contratto dati Address2
con le modifiche necessarie, un contratto dati Customer2
contenente il membro dati Address2
e un contratto dati PurchaseOrder2
contenente il membro dati Customer2
. Come nel caso precedente, anche il contratto di servizio deve essere sottoposto al controllo delle versioni.
Sebbene in questi esempi i nomi sono stati modificati (aggiungendo "2"), è consigliabile modificare gli spazi dei nomi anziché i nomi, aggiungendo un numero di versione o una data ai nuovi spazi dei nomi. Ad esempio, il contratto dati http://schemas.contoso.com/2005/05/21/PurchaseOrder
diventerebbe il contratto dati http://schemas.contoso.com/2005/10/14/PurchaseOrder
.
Per ulteriori informazioni, vedere Procedure consigliate: Controllo della versione del servizio.
In alcuni casi è necessario garantire la rigorosa conformità allo schema per i messaggi inviati dall'applicazione, ma non è possibile basarsi sui messaggi in ingresso per essere rigorosamente conformi allo schema. In questo caso, vi è il rischio che un messaggio in ingresso contenga dati estranei. I valori estranei vengono archiviati e restituiti da WCF e determinano quindi l'invio di messaggi non validi per lo schema. Per evitare questo problema, è necessario disattivare la funzionalità di creazione di sequenze di andata e ritorno. È possibile ottenere questo risultato in due modi.
- Non implementare l'interfaccia IExtensibleDataObject sui tipi utilizzati.
- Applicare un attributo ServiceBehaviorAttribute al contratto di servizio con la proprietà IgnoreExtensionDataObject impostata su true.
Per ulteriori informazioni sulle sequenze di andata e ritorno, vedere Contratti dati compatibili con versioni successive.
Controllo delle versioni quando la convalida dello schema non è necessaria
La rigorosa conformità allo schema è richiesta raramente. Molte piattaforme tollerano elementi aggiuntivi non descritti da un schema. Finché questi elementi sono tollerati, è possibile utilizzare l'insieme completo di funzionalità descritto in Controllo delle versioni dei contratti dati e Contratti dati compatibili con versioni successive. Di seguito sono riportate alcune linee guida consigliate.
È necessario attenersi esattamente ad alcune linee guida per inviare versioni nuove di un tipo quando ne è previsto uno precedente o inviare un tipo obsoleto quando ne è previsto uno nuovo. Altre linee guida non sono strettamente necessarie, ma sono elencate perché potrebbero essere interessate dagli sviluppi futuri del controllo delle versioni sullo schema.
- Non controllare le versioni dei contratti dati in base all'ereditarietà del tipo. Per creare versioni più recenti, modificare il contratto dati su un tipo esistente o creare un nuovo tipo non correlato.
- L'utilizzo dell'ereditarietà insieme ai contratti dati è consentito, purché l'ereditarietà non venga utilizzata come un meccanismo di controllo delle versioni e vengano seguite determinate regole. Se un tipo deriva da un determinato tipo di base, non è possibile fare in modo che derivi da un tipo di base diverso in una versione futura (a meno che abbia lo stesso contratto dati). Esiste un'unica eccezione a questa condizione: è 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 nomi identici a quelli di altri membri in qualsiasi possibile versione degli altri tipi nella gerarchia. In generale, l'utilizzo di membri dati con nomi identici a livelli diversi della stessa gerarchia di ereditarietà può causare gravi problemi di controllo delle versioni e deve essere evitato.
- A partire dalla prima versione di un contratto dati, implementare sempre IExtensibleDataObject per attivare le sequenze di andata e ritorno. Per ulteriori informazioni, vedere Contratti dati compatibili con versioni successive. Se sono state rilasciate una o più versioni di un tipo senza implementare questa interfaccia, è necessario implementarla nella prossima versione del tipo.
- Nelle versioni più recenti, non modificare il nome o lo spazio dei nomi del contratto 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 utilizzando i meccanismi adatti, ad esempio la proprietà Name di DataContractAttribute. Per ulteriori informazioni sull'assegnazione dei nomi, vedere Nomi di contratto dati.
- Nelle versioni più recenti, non modificare i nomi di qualsiasi membro dati. Se si modifica il nome del campo, della proprietà o dell'evento sottostante il membro dati, utilizzare la proprietà Name di DataMemberAttribute per mantenere il nome del membro dati esistente.
- Nelle versioni più recenti, non modificare il tipo di qualsiasi campo, proprietà o evento sottostante un membro dati in modo tale che il contratto dati risultante per quel membro dati venga modificato. Tenere presente che i tipi di interfaccia sono equivalenti a Object per l'identificazione del contratto dati previsto.
- Nelle versioni più recenti, non modificare l'ordine dei membri dati esistenti impostando la proprietà Order dell'attributo DataMemberAttribute.
- Nelle versioni più recenti, possono essere aggiunti nuovi membri dati. Questa operazione deve essere eseguita osservando le regole seguenti:
- La proprietà IsRequired deve essere sempre impostata sul valore predefinito false.
- Se un valore predefinito pari a null o a zero per il membro non è accettabile, è necessario fornire un metodo di callback mediante OnDeserializingAttribute per garantire un'impostazione predefinita adeguata qualora il membro non sia presente nel flusso in ingresso. Per ulteriori informazioni sul callback, vedere Callback di serializzazione a tolleranza di versione
- La proprietà Order su DataMemberAttribute deve essere utilizzata per assicurarsi che tutti i nuovi membri dati aggiunti siano posizionati dopo i membri dati esistenti. La procedura consigliata per eseguire questa operazione consiste nel verificare che la proprietà Order non sia impostata per alcun membro dati nella prima versione del contratto dati. 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 la proprietà Order impostata su 3 e così via. È consentito avere più membri dati impostati sullo stesso numero di Order.
- Non rimuovere i membri dati nelle versioni più recenti, anche se per la proprietà IsRequired è stato lasciato il valore predefinito false nelle versioni precedenti.
- Non modificare la proprietà IsRequired di qualsiasi membro dati esistente nel passaggio da una versione all'altra.
- Per i membri dati richiesti (dove IsRequired è true), non modificare la proprietà EmitDefaultValue nel passaggio da una versione all'altra.
- Non tentare di creare gerarchie di controlli delle versioni non collegati. Ovvero, deve esistere sempre un percorso, in almeno una direzione, da una qualsiasi versione a un'altra utilizzando solo le modifiche consentite dalle presenti linee guida.
Ad esempio, se la versione 1 di un contratto dati Person contiene solo il membro dati Name, non è necessario creare la versione 2a del contratto aggiungendo solo il membro Age e la versione 2b aggiungendo solo il membro Address. Il passaggio dalla versione 2a alla versione 2b coinvolgerebbe la rimozione di Age e l'aggiunta di Address; nella direzione opposta sarebbe necessario rimuovere Address e aggiungere Age. La rimozione di membri non è consentita dalle presenti linee guida. - In genere, è sconsigliabile creare nuovi sottotipi dei tipi di contratto dati esistenti in una nuova versione dell'applicazione. Analogamente, non è consigliabile creare nuovi contratti dati da utilizzare al posto dei membri dati dichiarati come Object o come tipi di interfaccia. La creazione di queste nuove classi è consentita solo quando si è sicuri di poter aggiungere i tipi nuovi all'elenco dei tipi conosciuti di tutte le istanze dell'applicazione precedente. Ad esempio, nella versione 1 dell'applicazione è possibile avere il tipo di contratto dati LibraryItem con i sottotipi del contratto dati Book e Newspaper. Pertanto, nell'elenco dei tipi conosciuti di LibraryItem sarebbero presenti Book e Newspaper. Si supponga di aggiungere un tipo Magazine alla versione 2 che è un sottotipo di LibraryItem. Se si invia un'istanza di Magazine dalla versione 2 alla versione 1, il contratto dati di Magazine non sarà presente nell'elenco dei tipi conosciuti e verrà generata un'eccezione.
- Non è consigliabile aggiungere o rimuovere membri di enumerazione tra diverse versioni. È inoltre sconsigliabile rinominare i membri di enumerazione, a meno che non si utilizzi la proprietà Name sull'attributo EnumMemberAttribute per mantenere gli stessi nomi nel modello del contratto dati.
- Gli insiemi sono intercambiabili nel modello del contratto dati, come descritto in Tipi di insiemi nei contratti dati. Ciò assicura un elevato grado di flessibilità. Tuttavia, accertarsi di non modificare inavvertitamente un tipo di insieme in modo non intercambiabile da una versione all'altra. Ad esempio, non modificare un insieme non personalizzato (ovvero senza l'attributo CollectionDataContractAttribute) in un insieme personalizzato o un insieme personalizzato in uno non personalizzato. Inoltre, non impostare le proprietà su CollectionDataContractAttribute da versione a versione. L'unica modifica consentita consiste nell'aggiunta di una proprietà Name o Namespace se il nome o lo spazio dei nomi del tipo di insieme sottostante sono stati modificati ed è necessario uniformare il nome e lo spazio dei nomi del contratto dati a quelli di una versione precedente.
Alcune delle linee guida elencate possono essere ignorate senza conseguenze se si verificano alcune circostanze speciali. Accertarsi di aver compreso tutti gli aspetti della serializzazione, della deserializzazione e dei meccanismi dello schema coinvolti prima di allontanarsi dalle linee guida.
Vedere anche
Riferimenti
Name
DataContractAttribute
Order
IsRequired
IExtensibleDataObject
ServiceBehaviorAttribute
ExtensionData
ExtensionDataObject
OnDeserializingAttribute
Concetti
Utilizzo di contratti dati
Controllo delle versioni dei contratti dati
Nomi di contratto dati
Contratti dati compatibili con versioni successive
Callback di serializzazione a tolleranza di versione