Versiebeheer van gegevenscontract
Naarmate toepassingen zich ontwikkelen, moet u mogelijk ook de gegevenscontracten wijzigen die door de services worden gebruikt. In dit onderwerp wordt uitgelegd hoe u versiegegevenscontracten kunt uitvoeren. In dit onderwerp worden de mechanismen voor versiebeheer van gegevenscontracten beschreven. Zie Best Practices: Data Contract Versioning voor een volledig overzicht en prescriptieve versiebeheerrichtlijnen.
Belangrijke versus niet-brekende wijzigingen
Wijzigingen in een gegevenscontract kunnen breken of breken. Wanneer een gegevenscontract op een ongebroken manier wordt gewijzigd, kan een toepassing met de oudere versie van het contract communiceren met een toepassing met behulp van de nieuwere versie en kan een toepassing met behulp van de nieuwere versie van het contract communiceren met een toepassing met behulp van de oudere versie. Aan de andere kant voorkomt een belangrijke wijziging communicatie in een of beide richtingen.
Wijzigingen in een type dat niet van invloed is op de manier waarop het wordt verzonden en ontvangen, zijn onbreekbaar. Dergelijke wijzigingen wijzigen het gegevenscontract niet, alleen het onderliggende type. U kunt bijvoorbeeld de naam van een veld op een vaste manier wijzigen als u vervolgens de Name eigenschap van de DataMemberAttribute eigenschap instelt op de naam van de oudere versie. De volgende code toont versie 1 van een gegevenscontract.
// Version 1
[DataContract]
public class Person
{
[DataMember]
private string Phone;
}
' Version 1
<DataContract()> _
Public Class Person
<DataMember()> _
Private Phone As String
End Class
De volgende code toont een vaste wijziging.
// Version 2. This is a non-breaking change because the data contract
// has not changed, even though the type has.
[DataContract]
public class Person
{
[DataMember(Name = "Phone")]
private string Telephone;
}
' Version 2. This is a non-breaking change because the data contract
' has not changed, even though the type has.
<DataContract()> _
Public Class Person
<DataMember(Name:="Phone")> _
Private Telephone As String
End Class
Sommige wijzigingen wijzigen de verzonden gegevens, maar kunnen wel of niet worden onderbroken. De volgende wijzigingen zijn altijd van kracht:
Name De of Namespace waarde van een gegevenscontract wijzigen.
De volgorde van gegevensleden wijzigen met behulp van de Order eigenschap van de DataMemberAttribute.
De naam van een gegevenslid wijzigen.
Het gegevenscontract van een gegevenslid wijzigen. U kunt bijvoorbeeld het type gegevenslid wijzigen van een geheel getal in een tekenreeks of van een type met een gegevenscontract met de naam 'Klant' in een type met een gegevenscontract met de naam 'Persoon'.
De volgende wijzigingen zijn ook mogelijk.
Gegevensleden toevoegen en verwijderen
In de meeste gevallen is het toevoegen of verwijderen van een gegevenslid geen belangrijke wijziging, tenzij u strikte geldigheid van het schema vereist (nieuwe exemplaren die geldig zijn voor het oude schema).
Wanneer een type met een extra veld wordt gedeserialiseerd in een type met een ontbrekend veld, wordt de extra informatie genegeerd. (Het kan ook worden opgeslagen voor retourdoeleinden; zie voor meer informatieDoorsturen compatibele gegevenscontracten).
Wanneer een type met een ontbrekend veld wordt gedeserialiseerd in een type met een extra veld, blijft het extra veld op de standaardwaarde staan, meestal nul of null
. (De standaardwaarde kan worden gewijzigd; zie voor meer informatieVersion-Tolerant Serialization Callbacks.)
U kunt bijvoorbeeld de CarV1
klasse op een client en de CarV2
klasse op een service gebruiken, of u kunt de CarV1
klasse voor een service en de CarV2
klasse op een client gebruiken.
// Version 1 of a data contract, on machine V1.
[DataContract(Name = "Car")]
public class CarV1
{
[DataMember]
private string Model;
}
// Version 2 of the same data contract, on machine V2.
[DataContract(Name = "Car")]
public class CarV2
{
[DataMember]
private string Model;
[DataMember]
private int HorsePower;
}
' Version 1 of a data contract, on machine V1.
<DataContract(Name:="Car")> _
Public Class CarV1
<DataMember()> _
Private Model As String
End Class
' Version 2 of the same data contract, on machine V2.
<DataContract(Name:="Car")> _
Public Class CarV2
<DataMember()> _
Private Model As String
<DataMember()> _
Private HorsePower As Integer
End Class
Het eindpunt van versie 2 kan gegevens naar het eindpunt van versie 1 verzenden. Het serialiseren van versie 2 van het Car
gegevenscontract levert XML op die vergelijkbaar is met de volgende.
<Car>
<Model>Porsche</Model>
<HorsePower>300</HorsePower>
</Car>
De deserialisatie-engine op V1 vindt geen overeenkomend gegevenslid voor het HorsePower
veld en verwijdert die gegevens.
Het eindpunt van versie 1 kan ook gegevens verzenden naar het eindpunt van versie 2. Het serialiseren van versie 1 van het Car
gegevenscontract levert XML op die vergelijkbaar is met de volgende.
<Car>
<Model>Porsche</Model>
</Car>
De deserializer van versie 2 weet niet waarop het HorsePower
veld moet worden ingesteld, omdat er geen overeenkomende gegevens in de binnenkomende XML zijn. In plaats daarvan wordt het veld ingesteld op de standaardwaarde van 0.
Vereiste gegevensleden
Een gegevenslid kan worden gemarkeerd als vereist door de IsRequired eigenschap van het DataMemberAttribute lid in te true
stellen op . Als de vereiste gegevens ontbreken tijdens het deserialisatieen, wordt er een uitzondering gegenereerd in plaats van het gegevenslid in te stellen op de standaardwaarde.
Het toevoegen van een vereist gegevenslid is een belangrijke wijziging. Dat wil gezegd, het nieuwere type kan nog steeds worden verzonden naar eindpunten met het oudere type, maar niet andersom. Het verwijderen van een gegevenslid dat is gemarkeerd als vereist in een eerdere versie, is ook een belangrijke wijziging.
Het wijzigen van de IsRequired eigenschapswaarde van waaruit true
false
dit niet breekt, maar als false
u deze wijzigt van naar true
, kan dit fouten veroorzaken als eerdere versies van het type geen gegevenslid in kwestie hebben.
Notitie
Hoewel de IsRequired eigenschap is ingesteld op true
, kunnen de binnenkomende gegevens null of nul zijn en moet een type worden voorbereid om deze mogelijkheid te verwerken. Gebruik dit niet IsRequired als een beveiligingsmechanisme om te beschermen tegen ongeldige binnenkomende gegevens.
Standaardwaarden weggelaten
Het is mogelijk (hoewel niet aanbevolen) om de EmitDefaultValue
eigenschap op het kenmerk false
DataMemberAttribute in te stellen op , zoals beschreven in standaardwaarden voor gegevenslid. Als deze instelling is false
, wordt het gegevenslid niet verzonden als deze is ingesteld op de standaardwaarde (meestal null of nul). Dit is op twee manieren niet compatibel met vereiste gegevensleden in verschillende versies:
Een gegevenscontract met een gegevenslid dat vereist is in één versie, kan geen standaardgegevens (null of nul) ontvangen van een andere versie waarin het gegevenslid is
EmitDefaultValue
ingesteldfalse
op .Een vereist gegevenslid dat is
EmitDefaultValue
ingesteld opfalse
kan niet worden gebruikt om de standaardwaarde (null of nul) te serialiseren, maar kan een dergelijke waarde ontvangen bij deserialisatie. Hiermee ontstaat een retourprobleem (gegevens kunnen worden gelezen, maar dezelfde gegevens kunnen niet worden weggeschreven).IsRequired
Als dat het geval istrue
false
enEmitDefaultValue
zich in één versie bevindt, moet dezelfde combinatie van toepassing zijn op alle andere versies, zodat geen enkele versie van het gegevenscontract een waarde kan produceren die niet resulteert in een retour.
Overwegingen voor schema's
Zie Data Contract Schema Reference voor een uitleg van het schema dat wordt geproduceerd voor gegevenscontracttypen.
Het schema dat WCF produceert voor gegevenscontracttypen maakt geen voorzieningen voor versiebeheer. Dat wil gezegd, het schema dat wordt geëxporteerd uit een bepaalde versie van een type, bevat alleen die gegevensleden die aanwezig zijn in die versie. Het implementeren van de IExtensibleDataObject interface wijzigt het schema voor een type niet.
Gegevensleden worden standaard als optionele elementen geëxporteerd naar het schema. Dat wil gezegd, de minOccurs
waarde (XML-kenmerk) is ingesteld op 0. Vereiste gegevensleden worden geëxporteerd met minOccurs
de set 1.
Veel van de wijzigingen die als nonbreaking worden beschouwd, worden daadwerkelijk onderbroken als strikte naleving van het schema vereist is. In het voorgaande voorbeeld zou een CarV1
exemplaar met alleen het Model
element valideren op basis van het CarV2
schema (dat beide Model
en Horsepower
, maar beide optioneel zijn). Het omgekeerde is echter niet waar: een CarV2
exemplaar zou de validatie van het CarV1
schema mislukken.
Retourtripping houdt ook enkele extra overwegingen in. Zie de sectie Schemaoverwegingen in Forward-Compatible Data Contracts voor meer informatie.
Andere toegestane wijzigingen
Het implementeren van de IExtensibleDataObject interface is een vaste wijziging. Retour-tripping-ondersteuning bestaat echter niet voor versies van het type vóór de versie waarin IExtensibleDataObject is geïmplementeerd. Zie Forward-Compatible Data Contracts voor meer informatie.
Opsommingen
Het toevoegen of verwijderen van een opsommingslid is een belangrijke wijziging. Als u de naam van een opsommingslid wijzigt, wordt de naam van een opsomming onderbroken, tenzij de contractnaam hetzelfde blijft als in de oude versie met behulp van het EnumMemberAttribute
kenmerk. Zie Opsommingstypen in gegevenscontracten voor meer informatie.
Verzamelingen
De meeste verzamelingswijzigingen zijn onbreekbaar omdat de meeste verzamelingstypen met elkaar kunnen worden uitgewisseld in het gegevenscontractmodel. Het aanpassen van een niet-aangepaste verzameling of omgekeerd is echter een belangrijke wijziging. Het wijzigen van de aanpassingsinstellingen van de verzameling is ook een belangrijke wijziging; dat wil zeggen dat u de naam en naamruimte van het gegevenscontract wijzigt, de naam van het herhalende element, de naam van het sleutelelement en de naam van het waardeelement. Zie Verzamelingstypen in Gegevenscontracten voor meer informatie over het aanpassen van verzamelingen.
Natuurlijk is het wijzigen van het gegevenscontract van de inhoud van een verzameling (bijvoorbeeld het wijzigen van een lijst met gehele getallen in een lijst met tekenreeksen) een belangrijke wijziging.
Zie ook
- Name
- DataMemberAttribute
- Name
- Namespace
- Order
- IsRequired
- SerializationException
- IExtensibleDataObject
- Callbacks voor serialisatie van versietolerante
- Aanbevolen procedures: Versiebeheer van gegevenscontract
- Gegevenscontracten gebruiken
- Gelijkwaardigheid van gegevenscontract
- Doorsturen compatibele gegevenscontracten