Metodtips: Versionshantering av datakontrakt
Det här avsnittet innehåller metodtips för att skapa datakontrakt som enkelt kan utvecklas över tid. Mer information om datakontrakt finns i avsnitten i Använda datakontrakt.
Anteckning om schemaverifiering
När du diskuterar versionshantering av datakontrakt är det viktigt att observera att datakontraktsschemat som exporteras av Windows Communication Foundation (WCF) inte har något versionsstöd, förutom att element markeras som valfria som standard.
Det innebär att inte ens det vanligaste versionsscenariot, till exempel att lägga till en ny datamedlem, kan implementeras på ett sätt som är sömlöst när det gäller ett visst schema. De nyare versionerna av ett datakontrakt (till exempel med en ny datamedlem) validerar inte med det gamla schemat.
Det finns dock många scenarier där strikt schemaefterlevnad inte krävs. Många webbtjänstplattformar, inklusive WCF- och XML-webbtjänster som skapats med ASP.NET, utför inte schemavalidering som standard och tolererar därför extra element som inte beskrivs i schemat. När du arbetar med sådana plattformar är många versionsscenarier enklare att implementera.
Det finns därför två uppsättningar med riktlinjer för versionshantering av datakontrakt: en uppsättning för scenarier där strikt schema giltighet är viktigt och en annan uppsättning för scenarier när den inte är det.
Versionshantering när schemaverifiering krävs
Om strikt schema giltighet krävs i alla riktningar (ny-till-gammal och gammal-till-ny), bör datakontrakt anses oföränderliga. Om versionshantering krävs ska ett nytt datakontrakt skapas, med ett annat namn eller namnområde, och tjänstkontraktet som använder datatypen ska versionshanteras i enlighet med detta.
Till exempel tar ett inköpsorderbearbetningstjänstkontrakt med namnet PoProcessing
med en PostPurchaseOrder
åtgärd en parameter som överensstämmer med ett PurchaseOrder
datakontrakt. PurchaseOrder
Om kontraktet måste ändras måste du skapa ett nytt datakontrakt, d.v.sPurchaseOrder2
. , som innehåller ändringarna. Du måste sedan hantera versionshantering på servicekontraktsnivå. Till exempel genom att skapa en PostPurchaseOrder2
åtgärd som tar parametern PurchaseOrder2
eller genom att skapa ett PoProcessing2
tjänstkontrakt där PostPurchaseOrder
åtgärden tar ett PurchaseOrder2
datakontrakt.
Observera att ändringar i datakontrakt som refereras till av andra datakontrakt även omfattar tjänstmodelllagret. I det föregående scenariot behöver datakontraktet PurchaseOrder
till exempel inte ändras. Den innehåller dock en datamedlem i ett Customer
datakontrakt, som i sin tur innehöll en datamedlem i datakontraktet Address
, som måste ändras. I så fall skulle du behöva skapa ett Address2
datakontrakt med nödvändiga ändringar, ett Customer2
datakontrakt som innehåller Address2
datamedlemmen och ett PurchaseOrder2
datakontrakt som innehåller en Customer2
datamedlem. Precis som i föregående fall måste även tjänstkontraktet vara versionshanterat.
Även om namnen i dessa exempel ändras (genom att lägga till "2" är rekommendationen att ändra namnområden i stället för namn genom att lägga till nya namnområden med ett versionsnummer eller ett datum. Datakontraktet http://schemas.contoso.com/2005/05/21/PurchaseOrder
skulle till exempel ändras till datakontraktet http://schemas.contoso.com/2005/10/14/PurchaseOrder
.
Mer information finns i Metodtips: Tjänstversioner.
Ibland måste du garantera strikt schemaefterlevnad för meddelanden som skickas av ditt program, men du kan inte förlita dig på att inkommande meddelanden är strikt schemakompatibla. I det här fallet finns det en risk att ett inkommande meddelande innehåller onödiga data. De överflödiga värdena lagras och returneras av WCF och resulterar därmed i att schema-ogiltiga meddelanden skickas. För att undvika det här problemet bör funktionen för avrundning inaktiveras. Det finns två sätt att göra detta på.
Implementera IExtensibleDataObject inte gränssnittet på någon av dina typer.
Tillämpa ett ServiceBehaviorAttribute attribut på tjänstkontraktet med egenskapen inställd på IgnoreExtensionDataObject
true
.
Mer information om rund-tripping finns i Framåtkompatibla datakontrakt.
Versionshantering när schemaverifiering inte krävs
Strikt schemaefterlevnad krävs sällan. Många plattformar tolererar extra element som inte beskrivs i ett schema. Så länge detta tolereras kan den fullständiga uppsättningen funktioner som beskrivs i Versionshantering av datakontrakt och framåtkompatibla datakontrakt användas. Följande riktlinjer rekommenderas.
Vissa av riktlinjerna måste följas exakt för att kunna skicka nya versioner av en typ där en äldre är förväntad eller skicka en gammal där den nya förväntas. Andra riktlinjer är inte absolut nödvändiga, men visas här eftersom de kan påverkas av framtiden för schemaversionshantering.
Försök inte att skapa versionsdatakontrakt efter typarv. Om du vill skapa senare versioner ändrar du antingen datakontraktet för en befintlig typ eller skapar en ny orelaterad typ.
Användning av arv tillsammans med datakontrakt tillåts, förutsatt att arv inte används som en versionsmekanism och att vissa regler följs. Om en typ härleds från en viss bastyp ska du inte göra så att den härleds från en annan bastyp i en framtida version (såvida den inte har samma datakontrakt). Det finns ett undantag: du kan infoga en typ i hierarkin mellan en datakontraktstyp och dess bastyp, men bara om den inte innehåller datamedlemmar med samma namn som andra medlemmar i eventuella versioner av de andra typerna i hierarkin. I allmänhet kan användning av datamedlemmar med samma namn på olika nivåer i samma arvshierarki leda till allvarliga versionsproblem och bör undvikas.
Börja med den första versionen av ett datakontrakt och implementera IExtensibleDataObject alltid för att aktivera avrundning. Mer information finns i Framåtkompatibla datakontrakt. Om du har släppt en eller flera versioner av en typ utan att implementera det här gränssnittet implementerar du det i nästa version av typen.
Ändra inte datakontraktets namn eller namnområde i senare versioner. Om du ändrar namnet eller namnområdet för den typ som ligger till grund för datakontraktet måste du bevara datakontraktets namn och namnområde med hjälp av lämpliga mekanismer, till exempel Name egenskapen för DataContractAttribute. Mer information om namngivning finns i Namn på datakontrakt.
Ändra inte namnen på några datamedlemmar i senare versioner. Om du ändrar namnet på fältet, egenskapen eller händelsen som ligger till grund för datamedlemmen använder du
Name
egenskapen DataMemberAttribute för för att bevara det befintliga datamedlemsnamnet.Ändra inte typen av fält, egenskap eller händelse som ligger till grund för en datamedlem i senare versioner, så att det resulterande datakontraktet för datamedlemmen ändras. Tänk på att gränssnittstyperna motsvarar för att Object fastställa det förväntade datakontraktet.
Ändra inte ordningen på befintliga datamedlemmar i senare versioner genom att Order justera egenskapen för attributet DataMemberAttribute .
I senare versioner kan nya datamedlemmar läggas till. De bör alltid följa dessa regler:
Egenskapen IsRequired ska alltid lämnas med standardvärdet
false
.Om ett standardvärde på eller noll för medlemmen är oacceptabelt bör en återanropsmetod tillhandahållas med hjälp av
null
OnDeserializingAttribute för att tillhandahålla en rimlig standard om medlemmen inte finns i den inkommande strömmen. Mer information om återanrop finns i Versionstoleranta serialiseringsåteranrop.Egenskapen DataMemberAttribute.Order bör användas för att se till att alla nyligen tillagda datamedlemmar visas efter de befintliga datamedlemmarna. Det rekommenderade sättet att göra detta är följande: Ingen av datamedlemmarna i den första versionen av datakontraktet bör ha sin
Order
egenskap angivna. Alla datamedlemmar som läggs till i version 2 av datakontraktet bör ha sinOrder
egenskap inställd på 2. Alla datamedlemmar som läggs till i version 3 av datakontraktet bör ha värdetOrder
3 och så vidare. Det är tillåtet att ha fler än en datamedlem inställd på sammaOrder
nummer.
Ta inte bort datamedlemmar i senare versioner, även om IsRequired egenskapen lämnades som standardegenskap
false
i tidigare versioner.Ändra inte egenskapen för
IsRequired
befintliga datamedlemmar från version till version.För nödvändiga datamedlemmar (där
IsRequired
är )true
ändrarEmitDefaultValue
du inte egenskapen från version till version.Försök inte skapa förgrenade versionshierarkier. Det vill sägs att det alltid bör finnas en sökväg i minst en riktning från en version till en annan version med endast de ändringar som tillåts i dessa riktlinjer.
Om version 1 av ett persondatakontrakt till exempel bara innehåller medlemmen Namndata bör du inte skapa version 2a av kontraktet och endast lägga till åldersmedlemmen och version 2b och endast lägga till adressmedlemmen. Att gå från 2a till 2b skulle innebära att ta bort ålder och lägga till adress; att gå i den andra riktningen skulle innebära att ta bort Adress och lägga till Ålder. Det är inte tillåtet att ta bort medlemmar i dessa riktlinjer.
Du bör vanligtvis inte skapa nya undertyper av befintliga datakontraktstyper i en ny version av ditt program. På samma sätt bör du inte skapa nya datakontrakt som används i stället för datamedlemmar som deklareras som objekt eller som gränssnittstyper. Att skapa dessa nya klasser tillåts endast när du vet att du kan lägga till de nya typerna i listan över kända typer av alla instanser av ditt gamla program. I version 1 av ditt program kan du till exempel ha datakontraktstypen LibraryItem med undertyperna Bok- och Tidningsdatakontrakt. LibraryItem skulle då ha en lista över kända typer som innehåller Bok och Tidning. Anta att du nu lägger till en tidskriftstyp i version 2 som är en undertyp av LibraryItem. Om du skickar en Magazine-instans från version 2 till version 1, hittas inte magazine-datakontraktet i listan över kända typer och ett undantag genereras.
Du bör inte lägga till eller ta bort uppräkningsmedlemmar mellan versioner. Du bör inte heller byta namn på uppräkningsmedlemmar, såvida du inte använder egenskapen Namn på
EnumMemberAttribute
attributet för att behålla deras namn i datakontraktsmodellen på samma sätt.Samlingar är utbytbara i datakontraktsmodellen enligt beskrivningen i Samlingstyper i datakontrakt. Detta ger stor flexibilitet. Kontrollera dock att du inte oavsiktligt ändrar en samlingstyp på ett icke-utbytbart sätt från version till version. Ändra till exempel inte från en icke-anpassad samling (det vill säga utan
CollectionDataContractAttribute
attributet) till en anpassad eller en anpassad samling till en icke-anpassad samling. Ändra inte heller egenskaperna förCollectionDataContractAttribute
från version till version. Den enda tillåtna ändringen är att lägga till en namn- eller namnområdesegenskap om den underliggande samlingstypens namn eller namnområde har ändrats och du behöver göra dess datakontraktsnamn och namnområde till samma som i en tidigare version.
Vissa av riktlinjerna som anges här kan ignoreras på ett säkert sätt när särskilda omständigheter gäller. Se till att du förstår mekanismerna för serialisering, deserialisering och schema innan du avviker från riktlinjerna.
Se även
- Name
- DataContractAttribute
- Order
- IsRequired
- IExtensibleDataObject
- ServiceBehaviorAttribute
- ExtensionData
- ExtensionDataObject
- OnDeserializingAttribute
- Använda datakontrakt
- Versionshantering av datakontrakt
- Namn på datakontrakt
- Framåtkompatibla datakontrakt
- Versionstoleranta återanrop för serialisering