Bagikan melalui


Mengimpor Skema untuk Menghasilkan Kelas

Untuk menghasilkan kelas dari skema yang dapat digunakan dengan Windows Communication Foundation (WCF), gunakan kelas XsdDataContractImporter. Topik ini menjelaskan proses dan variasinya.

Proses Impor

Proses impor skema dimulai dengan XmlSchemaSet dan menghasilkan CodeCompileUnit.

XmlSchemaSet adalah bagian dari Schema Object Model (SOM) .NET Framework yang mewakili sekumpulan dokumen skema bahasa definisi Skema XML (XSD). Untuk membuat objek XmlSchemaSet dari sekumpulan dokumen XSD, deserialisasi setiap dokumen ke dalam objek XmlSchema (menggunakan XmlSerializer) dan tambahkan objek ini ke yang baru XmlSchemaSet.

CodeCompileUnit adalah bagian dari Model Objek Dokumen Kode (CodeDOM) .NET Framework yang mewakili kode .NET Framework dengan cara abstrak. Untuk menghasilkan kode aktual dari CodeCompileUnit, gunakan subkelas dari kelas CodeDomProvider, seperti kelas CSharpCodeProvider atau VBCodeProvider.

Untuk mengimpor skema

  1. Buat instans XsdDataContractImporter.

  2. Opsional. Berikan CodeCompileUnit di konstruktor. Jenis yang dihasilkan selama impor skema ditambahkan ke instans CodeCompileUnit ini alih-alih dimulai dengan CodeCompileUnit kosong.

  3. Opsional. Panggil salah satu metode CanImport. Metode ini menentukan apakah skema yang diberikan adalah skema kontrak data yang valid dan dapat diimpor. Metode CanImport memiliki overload yang sama dengan Import (langkah berikutnya).

  4. Panggil salah satu metode Import yang overload, misalnya, metode Import(XmlSchemaSet).

    Overload paling sederhana mengambil XmlSchemaSet dan mengimpor semua jenis, termasuk jenis anonim, yang ditemukan dalam set skema tersebut. Overload lainnya memungkinkan Anda menentukan jenis XSD atau daftar jenis yang akan diimpor (dalam bentuk XmlQualifiedName atau koleksi objek XmlQualifiedName). Dalam hal ini, hanya jenis yang ditentukan yang diimpor. Overload mengambil XmlSchemaElement yang mengimpor elemen tertentu dari XmlSchemaSet, serta jenis terkaitnya (apakah itu anonim atau tidak). Overload ini mengembalikan XmlQualifiedName, yang mewakili nama kontrak data dari jenis yang dihasilkan untuk elemen ini.

    Beberapa panggilan metode Import mengakibatkan beberapa item ditambahkan ke CodeCompileUnit yang sama. Jenis tidak dihasilkan ke dalam CodeCompileUnit jika sudah ada di sana. Panggil Import beberapa kali pada XsdDataContractImporter yang sama alih-alih menggunakan beberapa objek XsdDataContractImporter. Ini adalah cara yang disarankan untuk menghindari jenis duplikat yang dihasilkan.

    Catatan

    Jika ada kegagalan selama impor, CodeCompileUnit akan berada dalam status yang tidak dapat diprediksi. Menggunakan CodeCompileUnit yang dihasilkan dari impor yang gagal dapat membuat Anda rentan terhadap keamanan.

  5. Akses CodeCompileUnit melalui properti CodeCompileUnit.

Opsi Impor: Menyesuaikan Jenis yang Dihasilkan

Anda dapat mengatur properti Options dari XsdDataContractImporter ke instans kelas ImportOptions untuk mengontrol berbagai aspek proses impor. Sejumlah opsi secara langsung memengaruhi jenis yang dihasilkan.

Mengontrol Tingkat Akses (GenerateInternal atau tombol /internal)

Ini sesuai dengan tombol /internal pada Alat Utilitas Metadata ServiceModel (Svcutil.exe).

Biasanya, jenis publik dihasilkan dari skema, dengan bidang privat dan properti anggota data publik yang cocok. Untuk menghasilkan jenis internal, atur properti GenerateInternal ke true.

Contoh berikut menunjukkan skema yang diubah menjadi kelas internal saat properti GenerateInternal diatur ke true.

[DataContract]
internal partial class Vehicle : IExtensibleDataObject
{
    private int yearField;
    private string colorField;

    [DataMember]
    internal int year
    {
        get { return this.yearField; }
        set { this.yearField = value; }
    }
    [DataMember]
    internal string color
    {
        get { return this.colorField; }
        set { this.colorField = value; }
    }

    private ExtensionDataObject extensionDataField;
    public ExtensionDataObject ExtensionData
    {
        get { return this.extensionDataField; }
        set { this.extensionDataField = value; }
    }
}
Class Vehicle
    Implements IExtensibleDataObject
    Private yearField As Integer
    Private colorField As String

    <DataMember()> _
    Friend Property year() As Integer
        Get
            Return Me.yearField
        End Get
        Set
            Me.yearField = value
        End Set
    End Property

    <DataMember()> _
    Friend Property color() As String
        Get
            Return Me.colorField
        End Get
        Set
            Me.colorField = value
        End Set
    End Property
    Private extensionDataField As ExtensionDataObject

    Public Property ExtensionData() As ExtensionDataObject _
        Implements IExtensibleDataObject.ExtensionData
        Get
            Return Me.extensionDataField
        End Get
        Set(ByVal value As ExtensionDataObject)
            Me.extensionDataField = value
        End Set
    End Property
End Class

Mengontrol Namespace (Namespace atau tombol /namespace)

Ini sesuai dengan tombol /namespace pada alat Svcutil.exe.

Biasanya, jenis yang dihasilkan dari skema dihasilkan ke dalam namespace .NET Framework, dengan setiap namespace XSD yang sesuai dengan namespace .NET Framework tertentu sesuai dengan pemetaan yang dijelaskan dalam Referensi Skema Kontrak Data. Anda dapat menyesuaikan pemetaan ini dengan properti Namespaces ke Dictionary<TKey,TValue>. Jika namespace XSD yang diberikan ditemukan dalam kamus, namespace layanan .NET Framework yang cocok juga diambil dari kamus Anda.

Misalnya, perhatikan skema berikut.

<xs:schema targetNamespace="http://schemas.contoso.com/carSchema">
  <xs:complexType name="Vehicle">
    <!-- details omitted... -->
  </xs:complexType>
</xs:schema>

Contoh berikut menggunakan properti Namespaces untuk memetakan namespace http://schemas.contoso.com/carSchema ke "Contoso.Cars".

XsdDataContractImporter importer = new XsdDataContractImporter();
importer.Options.Namespaces.Add(new KeyValuePair<string, string>("http://schemas.contoso.com/carSchema", "Contoso.Cars"));
Dim importer As New XsdDataContractImporter
importer.Options.Namespaces.Add(New KeyValuePair(Of String, String)("http://schemas.contoso.com/carSchema", "Contoso.Cars"))

Menambahkan SerializableAttribute (GenerateSerializable atau tombol /serializable)

Ini sesuai dengan tombol /serializable pada alat Svcutil.exe.

Terkadang penting bagi jenis yang dihasilkan dari skema agar dapat digunakan dengan mesin serialisasi runtime .NET Framework. Ini berguna saat menggunakan jenis untuk akses jauh .NET Framework. Untuk mengaktifkan ini, Anda harus menerapkan atribut SerializableAttribute ke jenis yang dihasilkan selain atribut DataContractAttribute reguler. Atribut dihasilkan secara otomatis jika opsi impor GenerateSerializable diatur ke true.

Contoh berikut menunjukkan kelas Vehicle yang dihasilkan dengan opsi impor GenerateSerializable diatur ke true.

[DataContract]
[Serializable]
public partial class Vehicle : IExtensibleDataObject
{
    // Code not shown.
    public ExtensionDataObject ExtensionData
    {
        get
        {
            throw new Exception("The method or operation is not implemented.");
        }
        set
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
}
<DataContract(), Serializable()> _
Partial Class Vehicle
    Implements IExtensibleDataObject
    Private extensionDataField As ExtensionDataObject

    ' Code not shown.

    Public Property ExtensionData() As ExtensionDataObject _
        Implements IExtensibleDataObject.ExtensionData
        Get
            Return Me.extensionDataField
        End Get
        Set(ByVal value As ExtensionDataObject)
            Me.extensionDataField = value
        End Set
    End Property

End Class

Menambahkan Dukungan Pengikatan Data (EnableDataBinding atau tombol /enableDataBinding)

Ini sesuai dengan tombol /enableDataBinding pada alat Svcutil.exe.

Terkadang, Anda mungkin ingin mengikat jenis yang dihasilkan dari skema ke komponen antarmuka pengguna grafis sehingga setiap pembaruan pada instans jenis ini akan secara otomatis memperbarui UI. XsdDataContractImporter dapat menghasilkan jenis yang mengimplementasikan antarmuka INotifyPropertyChanged sewaktu-waktu sehingga setiap perubahan properti memicu peristiwa. Jika Anda membuat jenis untuk digunakan dengan lingkungan pemrograman UI klien yang mendukung antarmuka ini (seperti Windows Presentation Foundation (WPF)), atur properti EnableDataBinding ke true untuk mengaktifkan fitur ini.

Contoh berikut menunjukkan kelas Vehicle yang dihasilkan dengan EnableDataBinding diatur ke true.

[DataContract]
public partial class Vehicle : IExtensibleDataObject, INotifyPropertyChanged
{
    private int yearField;
    private string colorField;

    [DataMember]
    public int year
    {
        get { return this.yearField; }
        set
        {
            if (this.yearField.Equals(value) != true)
            {
                this.yearField = value;
                this.RaisePropertyChanged("year");
            }
        }
    }
    [DataMember]
    public string color
    {
        get { return this.colorField; }
        set
        {
            if (this.colorField.Equals(value) != true)
            {
                this.colorField = value;
                this.RaisePropertyChanged("color");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler propertyChanged =
this.PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this,
new PropertyChangedEventArgs(propertyName));
        }
    }

    private ExtensionDataObject extensionDataField;
    public ExtensionDataObject ExtensionData
    {
        get { return this.extensionDataField; }
        set { this.extensionDataField = value; }
    }
}
Partial Class Vehicle
    Implements IExtensibleDataObject, INotifyPropertyChanged
    Private yearField As Integer
    Private colorField As String

    <DataMember()> _
    Public Property year() As Integer
        Get
            Return Me.yearField
        End Get
        Set
            If Me.yearField.Equals(value) <> True Then
                Me.yearField = value
                Me.RaisePropertyChanged("year")
            End If
        End Set
    End Property

    <DataMember()> _
    Public Property color() As String
        Get
            Return Me.colorField
        End Get
        Set
            If Me.colorField.Equals(value) <> True Then
                Me.colorField = value
                Me.RaisePropertyChanged("color")
            End If
        End Set
    End Property

    Public Event PropertyChanged As PropertyChangedEventHandler _
      Implements INotifyPropertyChanged.PropertyChanged

    Private Sub RaisePropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, _
         New PropertyChangedEventArgs(propertyName))
    End Sub

    Private extensionDataField As ExtensionDataObject

    Public Property ExtensionData() As ExtensionDataObject _
        Implements IExtensibleDataObject.ExtensionData
        Get
            Return Me.extensionDataField
        End Get
        Set(ByVal value As ExtensionDataObject)
            Me.extensionDataField = value
        End Set
    End Property

End Class

Opsi Impor: Memilih Jenis Koleksi

Dua pola khusus dalam XML mewakili kumpulan item: daftar item dan asosiasi antara satu item dan item lainnya. Berikut ini adalah contoh daftar string.

<People>
  <person>Alice</person>
  <person>Bob</person>
  <person>Charlie</person>
</People>

Berikut ini adalah contoh hubungan antara string dan bilangan bulat (city name dan population).

<Cities>
  <city>
    <name>Auburn</name>
    <population>40000</population>
  </city>
  <city>
    <name>Bellevue</name>
    <population>80000</population>
  </city>
  <city>
    <name>Cedar Creek</name>
    <population>10000</population>
  </city>
</Cities>

Catatan

Asosiasi apa pun juga dapat dianggap sebagai daftar. Misalnya, Anda dapat melihat asosiasi sebelumnya sebagai daftar objek city kompleks yang kebetulan memiliki dua bidang (bidang string dan bidang bilangan bulat). Kedua pola memiliki representasi dalam Skema XSD. Tidak ada cara untuk membedakan antara daftar dan asosiasi, sehingga pola tersebut selalu diperlakukan sebagai daftar kecuali anotasi khusus yang khusus untuk WCF ada dalam skema. Anotasi menunjukkan bahwa pola tertentu mewakili asosiasi. Untuk mengetahui informasi selengkapnya, lihat Referensi Skema Kontrak Data.

Biasanya, daftar diimpor sebagai kontrak data koleksi yang berasal dari Daftar Generik atau sebagai array .NET Framework, tergantung pada apakah skema mengikuti pola penamaan standar untuk koleksi atau tidak. Ini dijelaskan secara lebih rinci dalam Jenis Koleksi dalam Kontrak Data. Asosiasi biasanya diimpor sebagai Dictionary<TKey,TValue> atau kontrak data koleksi yang berasal dari objek kamus. Misalnya, perhatikan skema berikut.

<xs:complexType name="Vehicle">
  <xs:sequence>
    <xs:element name="year" type="xs:int"/>
    <xs:element name="color" type="xs:string"/>
    <xs:element name="passengers" type="people"/>
  </xs:sequence>
</xs:complexType>
<xs:complexType name="people">
  <xs:sequence>
    <xs:element name="person" type="xs:string" maxOccurs="unbounded" />
  </xs:sequence>
</xs:complexType>

Ini akan diimpor sebagai berikut (bidang ditampilkan alih-alih properti untuk keterbacaan).

[DataContract]
public partial class Vehicle : IExtensibleDataObject
{
    [DataMember] public int yearField;
    [DataMember] public string colorField;
    [DataMember] public people passengers;

    // Other code not shown.

    public ExtensionDataObject ExtensionData
    {
        get
        {
            throw new Exception("The method or operation is not implemented.");
        }
        set
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
}
[CollectionDataContract(ItemName = "person")]
public class people : List<string> { }
Public Partial Class Vehicle
    Implements IExtensibleDataObject

    <DataMember()> _
    Public yearField As Integer
    <DataMember()> _
    Public colorField As String
    <DataMember()> _
    Public passengers As people

    ' Other code not shown.

    Public Property ExtensionData() As ExtensionDataObject _
    Implements IExtensibleDataObject.ExtensionData
        Get
            Throw New Exception("The method or operation is not implemented.")
        End Get
        Set
            Throw New Exception("The method or operation is not implemented.")
        End Set
    End Property
End Class

<CollectionDataContract(ItemName:="person")> _
Public Class people
    Inherits List(Of String)
End Class

Dimungkinkan untuk menyesuaikan jenis koleksi yang dihasilkan untuk pola skema tersebut. Misalnya, Anda mungkin ingin menghasilkan koleksi yang berasal dari BindingList<T> alih-alih kelas List<T> untuk mengikat jenis ke kotak daftar dan memperbaruinya secara otomatis saat konten koleksi berubah. Untuk melakukan ini, atur properti ReferencedCollectionTypes kelas ImportOptions ke daftar jenis koleksi yang akan digunakan (selanjutnya dikenal sebagai jenis yang dirujuk). Saat mengimpor koleksi apa pun, daftar jenis koleksi yang direferensikan ini dipindai dan koleksi yang paling cocok digunakan jika ditemukan. Asosiasi hanya dicocokkan dengan jenis yang mengimplementasikan antarmuka IDictionary generik atau nongenerik, sementara daftar dicocokkan dengan jenis koleksi yang didukung.

Misalnya, jika properti ReferencedCollectionTypes diatur ke BindingList<T>, jenis people dalam contoh sebelumnya dihasilkan sebagai berikut.

[CollectionDataContract(ItemName = "person")]
public class people : BindingList<string> { }
<CollectionDataContract(ItemName:="person")> _
Public Class people
    Inherits BindingList(Of String)

Generik tertutup dianggap sebagai kecocokan terbaik. Misalnya, jika jenis BindingList(Of Integer) dan ArrayList diteruskan ke kumpulan jenis yang direferensikan, daftar bilangan bulat apa pun yang ditemukan dalam skema diimpor sebagai BindingList(Of Integer). Daftar lain, misalnya, List(Of String), diimpor sebagai ArrayList.

Jika jenis yang mengimplementasikan antarmuka IDictionary generik ditambahkan ke kumpulan jenis yang dirujuk, parameter jenisnya harus sepenuhnya terbuka atau tertutup penuh.

Duplikat tidak diizinkan. Misalnya, Anda tidak dapat menambahkan List(Of Integer) dan Collection(Of Integer) ke jenis yang dirujuk. Sehingga menentukan mana yang harus digunakan saat daftar bilangan bulat ditemukan dalam skema sulit dilakukan. Duplikat akan terdeteksi hanya jika ada jenis skema yang memperlihatkan masalah duplikat. Misalnya, jika skema yang diimpor tidak berisi daftar bilangan bulat, skema tersebut diizinkan untuk memiliki List(Of Integer) dan Collection(Of Integer) dalam koleksi jenis yang direferensikan, tetapi tidak akan memiliki pengaruh apa pun.

Mekanisme jenis koleksi yang dirujuk bekerja sama baiknya untuk koleksi jenis kompleks (termasuk koleksi dari koleksi lain), dan bukan hanya untuk koleksi primitif.

Properti ReferencedCollectionTypes sesuai dengan tombol /collectionType pada alat SvcUtil.exe. Perhatikan bahwa untuk mereferensikan beberapa jenis koleksi, tombol /collectionType harus ditentukan beberapa kali. Jika jenisnya tidak ada di MsCorLib.dll, perakitannya juga harus dirujuk menggunakan tombol /reference.

Opsi Impor: Mereferensikan Jenis yang Ada

Terkadang, jenis dalam skema sesuai dengan jenis .NET Framework yang ada, dan tidak perlu menghasilkan jenis ini dari awal. (Bagian ini hanya berlaku untuk jenis nonkoleksi. Untuk jenis koleksi, lihat bagian sebelumnya.)

Misalnya, Anda mungkin memiliki jenis kontrak data "Orang" di seluruh perusahaan standar yang selalu ingin Anda gunakan saat mewakili seseorang. Setiap kali beberapa layanan menggunakan jenis ini, dan skemanya muncul dalam metadata layanan, Anda mungkin ingin menggunakan kembali jenis Person yang ada saat mengimpor skema ini alih-alih menghasilkan yang baru untuk setiap layanan.

Untuk melakukan ini, teruskan daftar jenis .NET Framework yang ingin Anda gunakan kembali ke koleksi yang dikembalikan properti ReferencedTypes pada kelas ImportOptions. Jika salah satu dari jenis ini memiliki nama kontrak data dan namespace yang cocok dengan nama dan namespace dari jenis skema, perbandingan struktural dilakukan. Jika ditentukan bahwa jenis memiliki nama yang cocok dan struktur yang cocok, jenis .NET Framework yang ada digunakan kembali alih-alih menghasilkan yang baru. Jika hanya nama yang cocok tetapi bukan struktur, pengecualian akan diterapkan. Perhatikan bahwa tidak ada kelonggaran untuk pembuatan versi saat mereferensikan jenis (misalnya, menambahkan anggota data opsional baru). Struktur harus sama persis.

Diizinkan untuk menambahkan beberapa jenis dengan nama kontrak data dan namespace yang sama ke koleksi jenis yang direferensikan, selama tidak ada jenis skema yang diimpor dengan nama dan namespace tersebut. Ini memungkinkan Anda dengan mudah menambahkan semua jenis dalam perakitan ke koleksi tanpa khawatir tentang duplikat untuk jenis yang sebenarnya tidak terjadi dalam skema.

Properti ReferencedTypes sesuai dengan tombol /reference dalam mode operasi alat Svcutil.exe tertentu.

Catatan

Saat menggunakan Svcutil.exe atau (dalam Visual Studio) alat Tambahkan Referensi Layanan, semua jenis di MsCorLib.dll direferensikan secara otomatis.

Opsi Impor: Mengimpor Skema Non-DataContract sebagai jenis IXmlSerializable

XsdDataContractImporter mendukung subset terbatas dari skema. Jika konstruksi skema yang tidak didukung ada (misalnya, atribut XML), upaya impor gagal dengan pengecualian. Namun, mengatur properti ImportXmlType untuk true memperluas rentang skema yang didukung. Saat diatur ke true, XsdDataContractImporter menghasilkan jenis yang mengimplementasikan antarmuka IXmlSerializable. Ini memungkinkan akses langsung ke representasi XML dari jenis ini.

Pertimbangan Desain
  • Mungkin sulit untuk bekerja dengan representasi XML yang diketik dengan lemah secara langsung. Pertimbangkan untuk menggunakan mesin serialisasi alternatif, seperti XmlSerializer, untuk bekerja dengan skema yang tidak kompatibel dengan kontrak data dengan cara yang diketik dengan kuat. Untuk informasi selengkapnya, lihat Menggunakan Kelas XmlSerializer.

  • Beberapa konstruksi skema tidak dapat diimpor oleh XsdDataContractImporter bahkan ketika properti ImportXmlType diatur ke true. Sekali lagi, pertimbangkan untuk menggunakan XmlSerializer untuk kasus tersebut.

  • Konstruksi skema persis yang didukung saat ImportXmlType adalah true atau false dijelaskan dalam Referensi Skema Kontrak Data.

  • Skema untuk jenis IXmlSerializable yang dihasilkan tidak mempertahankan keakuratan saat diimpor dan diekspor. Artinya, mengekspor skema dari jenis yang dihasilkan dan mengimpor karena kelas tidak mengembalikan skema asli.

Dimungkinkan untuk menggabungkan opsi ImportXmlType dengan opsi ReferencedTypes yang dijelaskan sebelumnya. Untuk jenis yang harus dihasilkan sebagai implementasi IXmlSerializable, pemeriksaan struktural dilewati saat menggunakan fitur ReferencedTypes.

Opsi ImportXmlType ini sesuai dengan tombol /importXmlTypes pada alat Svcutil.exe.

Bekerja dengan Jenis IXmlSerializable yang Dihasilkan

Jenis IXmlSerializable yang dihasilkan berisi bidang privat, bernama "nodesField," yang mengembalikan array objek XmlNode. Saat mendeserialisasi instans jenis tersebut, Anda dapat mengakses data XML secara langsung melalui bidang ini dengan menggunakan Model Objek Dokumen XML. Saat menserialisasikan instans jenis ini, Anda dapat mengatur bidang ini ke data XML yang diinginkan dan akan diserialisasikan.

Hal ini dicapai melalui implementasi IXmlSerializable. Dalam jenis IXmlSerializable yang dihasilkan, implementasi ReadXml memanggil metode ReadNodes kelas XmlSerializableServices. Metode ini adalah metode pembantu yang mengonversi XML yang disediakan melalui XmlReader ke array objek XmlNode. Implementasi WriteXml melakukan kebalikannya dan mengonversi array objek XmlNode menjadi urutan panggilan XmlWriter. Ini dicapai menggunakan metode WriteNodes.

Dimungkinkan untuk menjalankan proses ekspor skema pada kelas IXmlSerializable yang dihasilkan. Seperti yang dinyatakan sebelumnya, Anda tidak akan mendapatkan skema asli kembali. Sebagai gantinya, Anda akan mendapatkan jenis XSD standar "anyType", yang merupakan wildcard untuk jenis XSD apa pun.

Ini dicapai dengan menerapkan atribut XmlSchemaProviderAttribute ke kelas IXmlSerializable yang dihasilkan dan menentukan metode yang memanggil metode AddDefaultSchema untuk menghasilkan jenis "anyType".

Catatan

Jenis XmlSerializableServices hanya ada untuk mendukung fitur khusus ini. Tidak disarankan untuk digunakan untuk tujuan lain.

Opsi Impor: Opsi Tingkat Lanjut

Berikut ini adalah opsi impor tingkat lanjut:

Lihat juga