Bagikan melalui


Pengganti DataContract

Sampel DataContract menunjukkan cara memproses seperti serialisasi, deserialisasi, ekspor skema, dan impor skema dapat disesuaikan menggunakan kelas pengganti kontrak data. Sampel ini menunjukkan cara menggunakan pengganti dalam klien dan skenario tempat data diserialisasikan dan ditransmisikan antara klien Windows Communication Foundation (WCF) dengan layanan.

Catatan

Prosedur penyiapan dan petunjuk pembuatan untuk sampel ini terdapat di akhir topik ini.

Sampel menggunakan kontrak layanan berikut:

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
[AllowNonSerializableTypes]
public interface IPersonnelDataService
{
    [OperationContract]
    void AddEmployee(Employee employee);

    [OperationContract]
    Employee GetEmployee(string name);
}

Operasi AddEmployee ini mengizinkan pengguna untuk menambah data karyawan baru dan operasi GetEmployee mendukung pencarian karyawan berdasarkan nama.

Operasi ini menggunakan jenis data berikut:

[DataContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
class Employee
{
    [DataMember]
    public DateTime dateHired;

    [DataMember]
    public Decimal salary;

    [DataMember]
    public Person person;
}

Dalam jenis Employee, kelas Person (ditunjukkan dalam kode sampel berikut) tidak dapat diserialisasikan oleh DataContractSerializer karena bukan merupakan kelas kontrak data yang valid.

public class Person
{
    public string firstName;

    public string lastName;

    public int age;

    public Person() { }
}

Anda dapat menerapkan atribut DataContractAttribute ke kelas Person, tetapi hal ini tidak selalu memungkinkan. Misalnya, kelas Person dapat ditentukan dalam rakitan terpisah yang tidak dapat Anda kontrol.

Dengan adanya pembatasan ini, salah satu cara untuk menserialisasikan kelas Person adalah menggantinya dengan kelas lain yang ditandai dengan DataContractAttribute dan menyalin data yang diperlukan ke kelas baru. Tujuannya adalah untuk membuat kelas Person muncul sebagai DataContract ke DataContractSerializer. Perhatikan bahwa ini adalah salah satu cara untuk menserialisasikan kelas kontrak non-data.

Sampel secara logis mengganti kelas Person dengan kelas yang berbeda bernama PersonSurrogated.

[DataContract(Name="Person", Namespace = "http://Microsoft.ServiceModel.Samples")]
public class PersonSurrogated
{
    [DataMember]
    public string FirstName;

    [DataMember]
    public string LastName;

    [DataMember]
    public int Age;
}

Pengganti kontrak data digunakan untuk mencapai penggantian ini. Pengganti kontrak data adalah kelas yang mengimplementasikan IDataContractSurrogate. Dalam sampel ini, kelas AllowNonSerializableTypesSurrogate mengimplementasikan antarmuka.

Dalam implementasi antarmuka, tugas pertama adalah membuat pemetaan jenis dari Person ke PersonSurrogated. Hal ini digunakan baik pada waktu serialisasi maupun pada waktu ekspor skema. Pemetaan ini dicapai dengan menerapkan metode GetDataContractType(Type).

public Type GetDataContractType(Type type)
{
    if (typeof(Person).IsAssignableFrom(type))
    {
        return typeof(PersonSurrogated);
    }
    return type;
}

Metode GetObjectToSerialize(Object, Type) memetakan instans Person ke instans PersonSurrogated selama serialisasi, seperti yang ditunjukkan pada kode sampel berikut.

public object GetObjectToSerialize(object obj, Type targetType)
{
    if (obj is Person)
    {
        Person person = (Person)obj;
        PersonSurrogated personSurrogated = new PersonSurrogated();
        personSurrogated.FirstName = person.firstName;
        personSurrogated.LastName = person.lastName;
        personSurrogated.Age = person.age;
        return personSurrogated;
    }
    return obj;
}

Metode GetDeserializedObject(Object, Type) ini menyediakan pemetaan terbalik untuk deserialisasi, seperti yang ditunjukkan pada kode sampel berikut.

public object GetDeserializedObject(object obj,
Type targetType)
{
    if (obj is PersonSurrogated)
    {
        PersonSurrogated personSurrogated = (PersonSurrogated)obj;
        Person person = new Person();
        person.firstName = personSurrogated.FirstName;
        person.lastName = personSurrogated.LastName;
        person.age = personSurrogated.Age;
        return person;
    }
    return obj;
}

Untuk memetakan kontrak data PersonSurrogated ke kelas Person yang tersedia selama impor skema, sampel mengimplementasikan metode GetReferencedTypeOnImport(String, String, Object), seperti yang ditunjukkan pada kode sampel berikut.

public Type GetReferencedTypeOnImport(string typeName,
               string typeNamespace, object customData)
{
if (
typeNamespace.Equals("http://schemas.datacontract.org/2004/07/DCSurrogateSample")
)
    {
         if (typeName.Equals("PersonSurrogated"))
        {
             return typeof(Person);
        }
     }
     return null;
}

Kode sampel berikut melengkapi implementasi antarmuka IDataContractSurrogate.

public System.CodeDom.CodeTypeDeclaration ProcessImportedType(
          System.CodeDom.CodeTypeDeclaration typeDeclaration,
          System.CodeDom.CodeCompileUnit compileUnit)
{
    return typeDeclaration;
}
public object GetCustomDataToExport(Type clrType,
                               Type dataContractType)
{
    return null;
}

public object GetCustomDataToExport(
System.Reflection.MemberInfo memberInfo, Type dataContractType)
{
    return null;
}
public void GetKnownCustomDataTypes(
        KnownTypeCollection customDataTypes)
{
    // It does not matter what we do here.
    throw new NotImplementedException();
}

Dalam sampel ini, pengganti diaktifkan pada ServiceModel oleh atribut yang disebut AllowNonSerializableTypesAttribute. Pengembang perlu menerapkan atribut ini pada kontrak layanannya seperti yang ditampilkan pada kontrak layanan IPersonnelDataService di atas. Atribut ini mengimplementasikan IContractBehavior dan menyiapkan pengganti pada operasi dalam metode ApplyClientBehavior dan ApplyDispatchBehavior.

Atribut tidak diperlukan dalam hal ini - digunakan untuk tujuan demonstrasi pada sampel ini. Pengguna juga dapat mengaktifkan pengganti dengan menambahkan IContractBehavior, IEndpointBehavior, atau IOperationBehavior yang serupa secara manual menggunakan kode atau menggunakan konfigurasi.

Implementasi IContractBehavior mencari operasi yang menggunakan DataContract dengan memeriksa apakah DataContractSerializerOperationBehavior telah terdaftar. Jika ya, maka properti DataContractSurrogate diatur dengan perilaku tersebut. Kode sampel berikut menunjukkan cara penyelesaiannya. Mengatur penggantian pada perilaku operasi memungkinkan untuk serialisasi dan deserialisasi.

public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime proxy)
{
    foreach (OperationDescription opDesc in description.Operations)
    {
        ApplyDataContractSurrogate(opDesc);
    }
}

public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatch)
{
    foreach (OperationDescription opDesc in description.Operations)
    {
        ApplyDataContractSurrogate(opDesc);
    }
}

private static void ApplyDataContractSurrogate(OperationDescription description)
{
    DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
    if (dcsOperationBehavior != null)
    {
        if (dcsOperationBehavior.DataContractSurrogate == null)
            dcsOperationBehavior.DataContractSurrogate = new AllowNonSerializableTypesSurrogate();
    }
}

Langkah tambahan perlu diambil untuk menyambungkan pengganti untuk dipakai selama menghasilkan metadata. Salah satu mekanisme untuk melakukan hal ini adalah menyediakan IWsdlExportExtension yang ditunjukkan oleh sampel ini. Cara lain adalah dengan memodifikasi WsdlExporter secara langsung.

Atribut AllowNonSerializableTypesAttribute menerapkan IWsdlExportExtension dan IContractBehavior. Dalam hal ini ekstensi dapat berupa IContractBehavior atau IEndpointBehavior. Implementasi metode IWsdlExportExtension.ExportContract tersebut mengaktifkan pengganti dengan menambahkannya kepada XsdDataContractExporter yang digunakan selama menghasilkan skema untuk DataContract. Cuplikan kode berikut menunjukkan cara melakukannya.

public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
{
    if (exporter == null)
        throw new ArgumentNullException("exporter");

    object dataContractExporter;
    XsdDataContractExporter xsdDCExporter;
    if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter), out dataContractExporter))
    {
        xsdDCExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);
        exporter.State.Add(typeof(XsdDataContractExporter), xsdDCExporter);
    }
    else
    {
        xsdDCExporter = (XsdDataContractExporter)dataContractExporter;
    }
    if (xsdDCExporter.Options == null)
        xsdDCExporter.Options = new ExportOptions();

    if (xsdDCExporter.Options.DataContractSurrogate == null)
        xsdDCExporter.Options.DataContractSurrogate = new AllowNonSerializableTypesSurrogate();
}

Saat Anda menjalankan sampel, klien memanggil AddEmployee diikuti oleh panggilan GetEmployee untuk memeriksa apakah panggilan pertama berhasil. Hasil dari permintaan operasi GetEmployee ditampilkan pada jendela konsol klien. Operasi GetEmployee harus berhasil dalam menemukan karyawan dan mencetak "ditemukan".

Catatan

Sampel ini menunjukkan cara menyambungkan pengganti untuk serialisasi, deserialisasi dan pembuatan metadata. Hal ini tidak dapat menampilkan cara menyambungkan pengganti untuk pembuatan kode dari metadata. Untuk melihat sampel dari cara pengganti dapat digunakan untuk menyambungkan ke pembuatan kode klien, lihat sampel Publikasi WSDL Kustom.

Untuk menyiapkan, membangun, dan menjalankan sampel

  1. Pastikan Anda telah melakukan Prosedur Penyiapan Satu Kali untuk Sampel Windows Communication Foundation.

  2. Untuk membangun solusi edisi C#, ikuti instruksi pada Membangun Sampel WCF.

  3. Untuk menjalankan sampel dalam konfigurasi satu atau lintas komputer, ikuti instruksi pada Menjalankan Sampel WCF.