Share via


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 Melanggar vs. Perubahan Yang Tidak Melanggar

Perubahan pada kontrak data dapat melanggar atau tidak melanggar. Ketika kontrak data diubah dengan cara yang tidak melanggar, aplikasi yang menggunakan versi kontrak yang lebih lama dapat berkomunikasi dengan aplikasi menggunakan versi yang lebih baru, dan begitu pun sebaliknya. 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 melanggar. Perubahan tersebut tidak mengubah kontrak data, hanya mengubah jenis yang mendasar. Misalnya, Anda dapat mengubah nama bidang dengan cara yang tidak melanggar jika Anda kemudian mengatur properti Name dari DataMemberAttribute ke nama versi yang lebih lama. Kode berikut menunjukkan versi 1 dari kontrak data.

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

// 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 melanggar. Perubahan berikut selalu melanggar:

  • Mengubah nilai Name atau Namespace dari kontrak data.

  • Mengubah urutan anggota data dengan menggunakan properti Order 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. (Jenis ini juga dapat disimpan untuk tujuan komunikasi dua arah; 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 kelas CarV1 pada klien dan kelas CarV2 pada layanan, atau Anda dapat menggunakan kelas CarV1 pada layanan dan kelas CarV2 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 berhasil mengirim data ke titik akhir versi 1. Serialisasi versi 2 dari kontrak data Car menangguhkan 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 HorsePower, dan membuang data tersebut.

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

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

Deserialisasi versi 2 tidak mengetahui apa yang harus diatur bidang 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 properti IsRequired dari DataMemberAttribute ke true. Jika data yang diperlukan hilang saat deserialisasi, pengecualian ditampilkan sebagai ganti 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 nilai properti IsRequired dari true ke false tidak melanggar, tetapi mengubahnya dari false ke true mungkin melanggar jika versi jenis sebelumnya tidak memiliki anggota data yang dimaksud.

Catatan

Meskipun properti IsRequired 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

Memungkinkan (meskipun tidak disarankan) untuk mengatur properti EmitDefaultValue pada atribut DataMemberAttribute ke false, seperti yang dijelaskan dalam Nilai Default Anggota Data. Jika pengaturan ini adalah false, anggota data tidak akan dipancarkan jika diatur ke nilai defaultnya (biasanya null atau nol). Nilai 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 memiliki EmitDefaultValue yang diatur ke false.

  • Anggota data yang diperlukan memiliki EmitDefaultValue yang diatur ke false tidak dapat digunakan untuk menserialisasikan nilai defaultnya (null atau nol), tetapi dapat menerima nilai tersebut pada deserialisasi. Hal ini menciptakan masalah komunikasi dua arah (data dapat dibaca tetapi data yang sama kemudian tidak dapat ditulis). Oleh karena itu, jika IsRequired adalah true dan EmitDefaultValue adalah false dalam satu versi, kombinasi yang sama harus berlaku untuk semua versi lain sehingga semua versi kontrak data dapat menghasilkan nilai dan komunikasi dua arah.

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 jenis versi tertentu hanya berisi anggota data yang ada dalam versi tersebut. Menerapkan antarmuka IExtensibleDataObject tidak mengubah skema untuk jenis.

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

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

Komunikasi dua arah juga memerlukan beberapa pertimbangan tambahan. Untuk informasi selengkapnya, lihat bagian "Pertimbangan Skema" di Kontrak Data yang Kompatibel Dengan Penerusan.

Perubahan Lain yang Diizinkan

Mengimplementasikan antarmuka IExtensibleDataObject adalah perubahan yang tidak melanggar. Namun, dukungan komunikasi dua arah tidak ada untuk versi jenis sebelumnya ke versi IExtensibleDataObject yang 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 merupakan pelanggaran, kecuali nama kontraknya tetap sama seperti di versi lama dengan menggunakan atribut EnumMemberAttribute. Untuk informasi selengkapnya, lihat Jenis Enumerasi dalam Kontrak Data.

Koleksi

Sebagian besar perubahan koleksi tidak melanggar 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 koleksi, lihat Jenis Koleksi dalam Kontrak Data.
Secara alami, mengubah kontrak data konten koleksi (misalnya, mengubah dari daftar bilangan bulat menjadi daftar string) adalah perubahan yang melanggar.

Lihat juga