Windows Communication Foundation (WCF) で使用できるスキーマからクラスを生成するには、 XsdDataContractImporter クラスを使用します。 このトピックでは、プロセスとバリエーションについて説明します。
インポート プロセス
スキーマのインポート プロセスは、 XmlSchemaSet から始まり、 CodeCompileUnitを生成します。
XmlSchemaSet
は、XML スキーマ定義言語 (XSD) スキーマ ドキュメントのセットを表す .NET Framework のスキーマ オブジェクト モデル (SOM) の一部です。 一連の XSD ドキュメントからXmlSchemaSet
オブジェクトを作成するには、各ドキュメントを (XmlSerializer を使用して) XmlSchema オブジェクトに逆シリアル化し、これらのオブジェクトを新しいXmlSchemaSet
に追加します。
CodeCompileUnit
は、.NET Framework コードを抽象的な方法で表す .NET Framework のコード ドキュメント オブジェクト モデル (CodeDOM) の一部です。
CodeCompileUnit
から実際のコードを生成するには、CSharpCodeProviderやVBCodeProvider クラスなどのCodeDomProvider クラスのサブクラスを使用します。
スキーマをインポートするには
XsdDataContractImporterのインスタンスを作成します。
任意。 コンストラクターに
CodeCompileUnit
を渡します。 スキーマのインポート中に生成された型は、空白のCodeCompileUnit
で始まるのではなく、このCodeCompileUnit
インスタンスに追加されます。任意。 CanImport メソッドのいずれかを呼び出します。 このメソッドは、指定されたスキーマが有効なデータ コントラクト スキーマであり、インポートできるかどうかを判断します。
CanImport
メソッドには、Import
と同じオーバーロードがあります (次の手順)。Import(XmlSchemaSet) メソッドなど、オーバーロードされた
Import
メソッドのいずれかを呼び出します。最も単純なオーバーロードは、
XmlSchemaSet
を受け取り、そのスキーマ セット内にある匿名型を含むすべての型をインポートします。 その他のオーバーロードを使用すると、XSD 型またはインポートする型の一覧を指定できます ( XmlQualifiedName またはXmlQualifiedName
オブジェクトのコレクションの形式)。 この場合、指定した型のみがインポートされます。 オーバーロードは、特定の要素をXmlSchemaSet
からインポートするXmlSchemaElementと、関連付けられた型 (匿名かどうか) を受け取ります。 このオーバーロードは、この要素に対して生成された型のデータ コントラクト名を表すXmlQualifiedName
を返します。Import
メソッドを複数回呼び出すと、同じCodeCompileUnit
に複数の項目が追加されます。 型が既に存在する場合、型はCodeCompileUnit
に生成されません。 複数のXsdDataContractImporter
オブジェクトを使用する代わりに、同じXsdDataContractImporter
でImport
を複数回呼び出します。 これは、重複する型が生成されないようにするための推奨される方法です。注
インポート中にエラーが発生した場合、
CodeCompileUnit
は予測できない状態になります。 インポートの失敗に起因するCodeCompileUnit
を使用すると、セキュリティの脆弱性が発生する可能性があります。CodeCompileUnit
プロパティを使用してCodeCompileUnitにアクセスします。
インポート オプション: 生成された型のカスタマイズ
XsdDataContractImporterのOptions プロパティを ImportOptions クラスのインスタンスに設定して、インポート プロセスのさまざまな側面を制御できます。 多くのオプションは、生成される型に直接影響します。
アクセス レベルの制御 (GenerateInternal または /internal スイッチ)
これは、ServiceModel メタデータ ユーティリティ ツール (Svcutil.exe) の /internal スイッチに対応します。
通常、パブリック型は、プライベート フィールドと一致するパブリック データ メンバー プロパティを使用して、スキーマから生成されます。 代わりに内部型を生成するには、 GenerateInternal プロパティを true
に設定します。
次の例は、 GenerateInternal プロパティが に設定されているときに内部クラスに変換されたスキーマを示しています。 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
名前空間の制御 (名前空間または /namespace スイッチ)
これは、Svcutil.exe
ツールの /namespace スイッチに対応します。
通常、スキーマから生成された型は .NET Framework 名前空間に生成されます。各 XSD 名前空間は、 データ コントラクト スキーマ リファレンスで説明されているマッピングに従って、特定の .NET Framework 名前空間に対応します。 このマッピングは、 Namespaces プロパティを使用して Dictionary<TKey,TValue>にカスタマイズできます。 特定の XSD 名前空間がディクショナリで見つかった場合、一致する .NET Framework 名前空間もディクショナリから取得されます。
たとえば、次のスキーマを考えてみましょう。
<xs:schema targetNamespace="http://schemas.contoso.com/carSchema">
<xs:complexType name="Vehicle">
<!-- details omitted... -->
</xs:complexType>
</xs:schema>
次の例では、 Namespaces
プロパティを使用して、 http://schemas.contoso.com/carSchema
名前空間を "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"))
SerializableAttribute (GenerateSerializable または /serializable スイッチ) の追加
これは、Svcutil.exe
ツールの /serializable スイッチに対応します。
スキーマから生成された型を .NET Framework ランタイムシリアル化エンジンで使用することが重要な場合があります。 これは、.NET Framework リモート処理に型を使用する場合に便利です。 これを有効にするには、通常のDataContractAttribute属性に加えて、生成された型にSerializableAttribute属性を適用する必要があります。
GenerateSerializable
インポート オプションが true
に設定されている場合、属性は自動的に生成されます。
次の例は、GenerateSerializable
インポート オプションを true
に設定して生成されたVehicle
クラスを示しています。
[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
データ バインディングのサポートの追加 (EnableDataBinding または /enableDataBinding スイッチ)
これは、Svcutil.exe ツールの /enableDataBinding スイッチに対応します。
場合によっては、スキーマから生成された型をグラフィカル ユーザー インターフェイス コンポーネントにバインドして、これらの型のインスタンスに対する更新によって UI が自動的に更新されるようにすることができます。
XsdDataContractImporter
は、プロパティの変更によってイベントがトリガーされるように、INotifyPropertyChanged インターフェイスを実装する型を生成できます。 このインターフェイス (Windows Presentation Foundation (WPF) など) をサポートするクライアント UI プログラミング環境で使用する型を生成する場合は、 EnableDataBinding プロパティを true
に設定してこの機能を有効にします。
次の例は、EnableDataBindingが true
に設定された状態で生成されたVehicle
クラスを示しています。
[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
インポート オプション: コレクション型の選択
XML の 2 つの特殊なパターンは、項目のコレクションを表します。項目のリストと、1 つの項目と別の項目の間の関連付け。 文字列の一覧の例を次に示します。
<People>
<person>Alice</person>
<person>Bob</person>
<person>Charlie</person>
</People>
文字列と整数 (city name
と 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>
注
関連付けはすべてリストと見なすこともできます。 たとえば、上記の関連付けを、2 つのフィールド (文字列フィールドと整数フィールド) がある複合 city
オブジェクトの一覧として表示できます。 どちらのパターンにも XSD スキーマの表現があります。 リストと関連付けを区別する方法がないため、WCF に固有の特別な注釈がスキーマに存在しない限り、このようなパターンは常にリストとして扱われます。 注釈は、特定のパターンが関連付けを表していることを示します。 詳細については、「 データ コントラクト スキーマ リファレンス」を参照してください。
通常、リストは、スキーマがコレクションの標準の名前付けパターンに従っているかどうかに応じて、ジェネリック リストから派生したコレクション データ コントラクトまたは .NET Framework 配列としてインポートされます。 詳細については、「 データ コントラクトのコレクション型」を参照してください。 通常、関連付けは、ディクショナリ オブジェクトから派生した Dictionary<TKey,TValue> またはコレクション データ コントラクトとしてインポートされます。 たとえば、次のスキーマを考えてみましょう。
<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>
これは次のようにインポートされます (読みやすくするためにプロパティの代わりにフィールドが表示されます)。
[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
このようなスキーマ パターンに対して生成されるコレクション型をカスタマイズできます。 たとえば、List<T> クラスではなくBindingList<T>から派生したコレクションを生成して、型をリスト ボックスにバインドし、コレクションの内容が変更されたときに自動的に更新されるようにすることができます。 これを行うには、ImportOptions クラスのReferencedCollectionTypes プロパティを使用するコレクション型の一覧 (以下、参照される型と呼ばれます) に設定します。 コレクションをインポートするときに、参照されるコレクションの種類のこの一覧がスキャンされ、最適に一致するコレクションが見つかった場合に使用されます。 関連付けは、ジェネリックまたは非ジェネリック IDictionary インターフェイスを実装する型に対してのみ照合されますが、リストはサポートされている任意のコレクション型と照合されます。
たとえば、 ReferencedCollectionTypes プロパティが BindingList<T>に設定されている場合、前の例の people
型は次のように生成されます。
[CollectionDataContract(ItemName = "person")]
public class people : BindingList<string> { }
<CollectionDataContract(ItemName:="person")> _
Public Class people
Inherits BindingList(Of String)
閉じたジェネリックが最適な一致と見なされます。 たとえば、 BindingList(Of Integer)
型と ArrayList 型が参照先の型のコレクションに渡される場合、スキーマで見つかった整数のリストは BindingList(Of Integer)
としてインポートされます。 その他のリスト ( List(Of String)
など) は、 ArrayList
としてインポートされます。
ジェネリック IDictionary
インターフェイスを実装する型が参照される型のコレクションに追加される場合、その型パラメーターは完全に開いているか、完全に閉じている必要があります。
複製は使用できません。 たとえば、参照先の型に List(Of Integer)
と Collection(Of Integer)
の両方を追加することはできません。 そのため、スキーマで整数のリストが見つかった場合に使用する必要がある値を特定できなくなります。 重複が検出されるのは、重複の問題を公開するスキーマに型がある場合のみです。 たとえば、インポートされたスキーマに整数のリストが含まれていない場合は、参照される型コレクションに List(Of Integer)
と Collection(Of Integer)
の両方を持つことができますが、どちらも影響を与えません。
参照されるコレクション型のメカニズムは、プリミティブのコレクションだけでなく、複合型のコレクション (他のコレクションのコレクションを含む) にも同様に適しています。
ReferencedCollectionTypes
プロパティは、SvcUtil.exe ツールの /collectionType スイッチに対応します。 複数のコレクション型を参照するには、 /collectionType スイッチを複数回指定する必要があります。 型が MsCorLib.dllにない場合は、そのアセンブリも /reference スイッチを使用して参照する必要があります。
インポート オプション: 既存の型の参照
スキーマ内の型が既存の .NET Framework 型に対応する場合があり、これらの型を最初から生成する必要はありません。 (このセクションは、非コレクション型にのみ適用されます。コレクションの種類については、前のセクションを参照してください)。
たとえば、標準の会社全体の "Person" データ コントラクトの種類があり、ユーザーを表すときに常に使用する必要があるとします。 一部のサービスがこの型を使用し、そのスキーマがサービス メタデータに表示される場合は常に、すべてのサービスに対して新しいスキーマを生成するのではなく、このスキーマをインポートするときに既存の Person
型を再利用できます。
これを行うには、再利用する .NET Framework 型の一覧を、ImportOptions クラスで返されるReferencedTypes プロパティのコレクションに渡します。 これらの型のいずれかに、スキーマ型の名前と名前空間と一致するデータ コントラクト名と名前空間がある場合は、構造比較が実行されます。 型に一致する名前と一致する構造体の両方が含まれていると判断された場合は、新しい .NET Framework 型を生成する代わりに、既存の .NET Framework 型が再利用されます。 名前だけが構造体と一致するが、構造体に一致しない場合は、例外がスローされます。 型を参照する場合 (たとえば、新しい省略可能なデータ メンバーを追加するなど) は、バージョン管理の許容量がないことに注意してください。 構造体は正確に一致する必要があります。
同じデータ コントラクト名と名前空間を持つ複数の型を参照先の型コレクションに追加することは、その名前と名前空間でスキーマ型がインポートされない限り有効です。 これにより、実際にスキーマで発生しない型の重複を気にすることなく、アセンブリ内のすべての型をコレクションに簡単に追加できます。
ReferencedTypes
プロパティは、Svcutil.exe ツールの特定の動作モードでの /reference スイッチに対応します。
注
Svcutil.exe または (Visual Studio で) サービス参照の追加 ツールを使用すると、MsCorLib.dll 内のすべての型が自動的に参照されます。
インポート オプション: 非 DataContract スキーマを IXmlSerializable 型としてインポートする
XsdDataContractImporterでは、スキーマの限られたサブセットがサポートされます。 サポートされていないスキーマコンストラクト (XML 属性など) が存在する場合、インポートの試行は例外で失敗します。 ただし、 ImportXmlType プロパティを true
に設定すると、サポートされるスキーマの範囲が拡張されます。
true
に設定すると、XsdDataContractImporterはIXmlSerializable インターフェイスを実装する型を生成します。 これにより、これらの型の XML 表現に直接アクセスできます。
設計に関する考慮事項
弱く型指定された XML 表現を直接操作するのは困難な場合があります。 XmlSerializerなどの代替シリアル化エンジンを使用して、厳密に型指定された方法でデータ コントラクトと互換性のないスキーマを操作することを検討してください。 詳細については、「 XmlSerializer クラスの使用」を参照してください。
ImportXmlType プロパティが
true
に設定されている場合でも、一部のスキーマ コンストラクトはXsdDataContractImporterによってインポートできません。 ここでも、このような場合は XmlSerializer の使用を検討してください。ImportXmlTypeが
true
またはfalse
の両方でサポートされる正確なスキーマ構造については、「データ コントラクト スキーマ リファレンス」を参照してください。生成された IXmlSerializable 型のスキーマは、インポートおよびエクスポート時に忠実性を保持しません。 つまり、生成された型からスキーマをエクスポートし、クラスとしてインポートしても元のスキーマは返されません。
ImportXmlType オプションと、前述の ReferencedTypes オプションを組み合わせることができます。 IXmlSerializable実装として生成する必要がある型の場合、ReferencedTypes機能を使用する場合、構造チェックはスキップされます。
ImportXmlType オプションは、Svcutil.exe ツールの /importXmlTypes スイッチに対応します。
生成された IXmlSerializable 型の操作
生成された IXmlSerializable
型には、 XmlNode オブジェクトの配列を返す "nodesField" という名前のプライベート フィールドが含まれています。 このような型のインスタンスを逆シリアル化する場合は、XML ドキュメント オブジェクト モデルを使用して、このフィールドを介して XML データに直接アクセスできます。 この型のインスタンスをシリアル化するときに、このフィールドを目的の XML データに設定すると、シリアル化されます。
これは、 IXmlSerializable
実装によって実現されます。 生成されたIXmlSerializable
型では、ReadXml実装は、XmlSerializableServices クラスのReadNodes メソッドを呼び出します。 このメソッドは、 XmlReader を介して提供された XML を XmlNode オブジェクトの配列に変換するヘルパー メソッドです。
WriteXml実装では逆の処理が行われ、XmlNode
オブジェクトの配列が一連のXmlWriter呼び出しに変換されます。 これは、 WriteNodes メソッドを使用して行います。
生成された IXmlSerializable
クラスでスキーマ エクスポート プロセスを実行できます。 前述のように、元のスキーマは返されません。 代わりに、"anyType" 標準 XSD 型が取得されます。これは、任意の XSD 型のワイルドカードです。
これを実現するには、生成されたIXmlSerializable
クラスにXmlSchemaProviderAttribute属性を適用し、AddDefaultSchema メソッドを呼び出して "anyType" 型を生成するメソッドを指定します。
注
XmlSerializableServices型は、この特定の機能をサポートするためだけに存在します。 他の目的で使用することはお勧めしません。
インポート オプション: 詳細オプション
高度なインポート オプションを次に示します。
CodeProvider プロパティ。 生成されたクラスのコードの生成に使用する CodeDomProvider を指定します。 インポート メカニズムは、 CodeDomProvider がサポートしていない機能を回避しようとします。 CodeProviderが設定されていない場合は、.NET Framework 機能の完全なセットが制限なしで使用されます。
DataContractSurrogate プロパティ。 IDataContractSurrogate実装は、このプロパティで指定できます。 IDataContractSurrogateはインポート プロセスをカスタマイズします。 詳細については、「 データ コントラクトサロゲート」を参照してください。 既定では、サロゲートは使用されません。