Penerapan Versi Kontrak Data

Seiring berkembangnya aplikasi, Anda mungkin juga harus mengubah kontrak data yang digunakan layanan. Topik ini menjelaskan cara membuat versi kontrak data. Topik ini menjelaskan mekanisme penerapan versi kontrak data. Untuk gambaran umum lengkap dan panduan penerapan versi preskriptif, lihat Praktik Terbaik: Penerapan Versi Kontrak Data.

Perubahan Mencolok vs. Tidak Terputus

Perubahan pada kontrak data dapat melanggar atau tidak pecah. Ketika kontrak data diubah dengan cara yang tidak pecah, aplikasi yang menggunakan versi kontrak yang lebih lama dapat berkomunikasi dengan aplikasi menggunakan versi yang lebih baru, dan aplikasi yang menggunakan versi kontrak yang lebih baru dapat berkomunikasi dengan aplikasi menggunakan versi yang lebih lama. Di sisi lain, perubahan yang melanggar mencegah komunikasi di satu atau kedua arah.

Setiap perubahan pada jenis yang tidak memengaruhi cara pengiriman dan penerimaannya tidak terpecahkan. Perubahan tersebut tidak mengubah kontrak data, hanya jenis yang mendasar. Misalnya, Anda dapat mengubah nama bidang dengan cara yang tidak pecah jika Anda kemudian mengatur Name properti ke DataMemberAttribute nama versi yang lebih lama. Kode berikut menunjukkan kontrak data versi 1.

// Version 1
[DataContract]
public class Person
{
    [DataMember]
    private string Phone;
}
' Version 1
<DataContract()> _
Public Class Person
    <DataMember()> _
    Private Phone As String
End Class

Kode berikut menunjukkan perubahan yang tidak memisahkan.

// 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

Beberapa perubahan mengubah data yang dikirimkan, tetapi mungkin atau mungkin tidak rusak. Perubahan berikut selalu melanggar:

  • Mengubah Name nilai atau Namespace kontrak data.

  • Mengubah urutan anggota data dengan menggunakan Order properti dari DataMemberAttribute.

  • Mengganti nama anggota data.

  • Mengubah kontrak data anggota data. Misalnya, mengubah jenis anggota data dari bilangan bulat menjadi string, atau dari jenis dengan kontrak data bernama "Pelanggan" menjadi jenis dengan kontrak data bernama "Orang".

Perubahan berikut juga dimungkinkan.

Menambahkan dan Menghapus Anggota Data

Dalam kebanyakan kasus, menambahkan atau menghapus anggota data bukanlah perubahan yang melanggar, kecuali Anda memerlukan validitas skema yang ketat (instans baru yang memvalidasi terhadap skema lama).

Saat jenis dengan bidang tambahan dideserialisasi ke dalam jenis dengan bidang yang hilang, informasi tambahan diabaikan. (Ini juga dapat disimpan untuk tujuan round-tripping; untuk informasi selengkapnya, lihat Kontrak Data yang Kompatibel Dengan Penerusan).

Saat jenis dengan bidang yang hilang dideserialisasi ke dalam jenis dengan bidang tambahan, bidang tambahan dibiarkan pada nilai defaultnya, biasanya nol atau null. (Nilai default dapat diubah; untuk informasi selengkapnya, lihat Panggilan Balik Serialisasi Toleran Versi.)

Misalnya, Anda dapat menggunakan CarV1 kelas pada klien dan CarV2 kelas pada layanan, atau Anda dapat menggunakan CarV1 kelas pada layanan dan CarV2 kelas pada klien.

// 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

Titik akhir versi 2 dapat berhasil mengirim data ke titik akhir versi 1. Serialisasi versi 2 dari Car kontrak data menghasilkan XML yang mirip dengan yang berikut ini.

<Car>  
    <Model>Porsche</Model>  
    <HorsePower>300</HorsePower>  
</Car>  

Mesin deserialisasi pada V1 tidak menemukan anggota data yang cocok untuk bidang , dan membuang data tersebut HorsePower .

Selain itu, titik akhir versi 1 dapat mengirim data ke titik akhir versi 2. Serialisasi versi 1 dari Car kontrak data menghasilkan XML yang mirip dengan yang berikut ini.

<Car>  
    <Model>Porsche</Model>  
</Car>  

Deserializer versi 2 tidak tahu apa yang harus diatur bidangnya HorsePower , karena tidak ada data yang cocok di XML masuk. Sebagai gantinya, bidang diatur ke nilai default 0.

Anggota Data yang Diperlukan

Anggota data dapat ditandai sebagai diperlukan dengan mengatur IsRequired properti ke DataMemberAttributetrue. Jika data yang diperlukan hilang saat deserialisasi, pengecualian dilemparkan alih-alih mengatur anggota data ke nilai defaultnya.

Menambahkan anggota data yang diperlukan adalah perubahan yang melanggar. Artinya, jenis yang lebih baru masih dapat dikirim ke titik akhir dengan jenis yang lebih lama, tetapi tidak sebaliknya. Menghapus anggota data yang ditandai sebagaimana diperlukan dalam versi sebelumnya juga merupakan perubahan yang melanggar.

Mengubah IsRequired nilai properti dari true ke false tidak melanggar, tetapi mengubahnya dari false menjadi true mungkin rusak jika versi jenis sebelumnya tidak memiliki anggota data yang dimaksud.

Catatan

IsRequired Meskipun properti diatur ke true, data masuk mungkin null atau nol, dan jenis harus disiapkan untuk menangani kemungkinan ini. Jangan gunakan IsRequired sebagai mekanisme keamanan untuk melindungi dari data masuk yang buruk.

Nilai Default yang Dihilangkan

Dimungkinkan (meskipun tidak disarankan) untuk mengatur EmitDefaultValue properti pada atribut DataMemberAttribute ke false, seperti yang dijelaskan dalam Nilai Default Anggota Data. Jika pengaturan ini adalah false, anggota data tidak akan dikeluarkan jika diatur ke nilai defaultnya (biasanya null atau nol). Ini tidak kompatibel dengan anggota data yang diperlukan dalam versi yang berbeda dengan dua cara:

  • Kontrak data dengan anggota data yang diperlukan dalam satu versi tidak dapat menerima data default (null atau nol) dari versi yang berbeda di mana anggota data telah EmitDefaultValue mengatur ke false.

  • Anggota data yang diperlukan yang telah EmitDefaultValue diatur ke false tidak dapat digunakan untuk menserialisasikan nilai defaultnya (null atau nol), tetapi dapat menerima nilai tersebut pada deserialisasi. Ini membuat masalah round-tripping (data dapat dibaca tetapi data yang sama kemudian tidak dapat ditulis). Oleh karena itu, jika IsRequired adalah true dan EmitDefaultValue berada false dalam satu versi, kombinasi yang sama harus berlaku untuk semua versi lain sehingga tidak ada versi kontrak data yang dapat menghasilkan nilai yang tidak menghasilkan perjalanan pulang pergi.

Pertimbangan Skema

Untuk penjelasan tentang skema apa yang diproduksi untuk jenis kontrak data, lihat Referensi Skema Kontrak Data.

Skema yang dihasilkan WCF untuk jenis kontrak data tidak membuat ketentuan untuk penerapan versi. Artinya, skema yang diekspor dari versi tertentu dari jenis hanya berisi anggota data yang ada dalam versi tersebut. IExtensibleDataObject Menerapkan antarmuka tidak mengubah skema untuk jenis.

Anggota data diekspor ke skema sebagai elemen opsional secara default. Artinya, minOccurs nilai (atribut XML) diatur ke 0. Anggota data yang diperlukan diekspor dengan minOccurs diatur ke 1.

Banyak perubahan yang dianggap tidak pecah sebenarnya melanggar jika kepatuhan ketat terhadap skema diperlukan. Dalam contoh sebelumnya, CarV1 instans hanya Model dengan elemen akan memvalidasi terhadap CarV2 skema (yang memiliki dan ModelHorsepower, tetapi keduanya bersifat opsional). Namun, kebalikannya tidak benar: CarV2 instans akan gagal validasi terhadap CarV1 skema.

Round-tripping juga memerlukan beberapa pertimbangan tambahan. Untuk informasi selengkapnya, lihat bagian "Pertimbangan Skema" di Kontrak Data yang Kompatibel Dengan Penerusan.

Perubahan Lain yang Diizinkan

Menerapkan IExtensibleDataObject antarmuka adalah perubahan yang tidak memisahkan. Namun, dukungan round-tripping tidak ada untuk versi jenis sebelum versi yang IExtensibleDataObject diimplementasikan. Untuk informasi selengkapnya, lihat Kontrak Data yang Kompatibel Dengan Penerusan.

Enumerasi

Menambahkan atau menghapus anggota enumerasi adalah perubahan yang melanggar. Mengubah nama anggota enumerasi rusak, kecuali nama kontraknya tetap sama seperti di versi lama dengan menggunakan EnumMemberAttribute atribut . Untuk informasi selengkapnya, lihat Jenis Enumerasi dalam Kontrak Data.

Koleksi

Sebagian besar perubahan koleksi tidak terputus karena sebagian besar jenis koleksi dapat dipertukarkan satu sama lain dalam model kontrak data. Namun, membuat koleksi yang tidak terbiasa disesuaikan atau sebaliknya adalah perubahan yang melanggar. Selain itu, mengubah pengaturan kustomisasi koleksi adalah perubahan yang melanggar; yaitu, mengubah nama kontrak data dan namespace layanannya, mengulangi nama elemen, nama elemen kunci, dan nama elemen nilai. Untuk informasi selengkapnya tentang kustomisasi pengumpulan, lihat Jenis Koleksi di Kontrak Data.
Secara alami, mengubah kontrak data konten koleksi (misalnya, mengubah dari daftar bilangan bulat menjadi daftar string) adalah perubahan yang melanggar.

Lihat juga