若要從 Windows Communication Foundation (WCF) 可使用的架構產生類別,請使用 類別 XsdDataContractImporter 。 本主題描述過程和變化。
匯入程式
架構匯入程式會以XmlSchemaSet開始,並產生CodeCompileUnit。
XmlSchemaSet是 .NET Framework 架構物件模型 (SOM) 的一部分,代表一組 XML 架構定義語言 (XSD) 架構檔。 若要從一組 XSD 檔案建立 XmlSchemaSet 物件,請將每個檔案還原串行化為 XmlSchema 物件(使用 XmlSerializer),並將這些物件新增至新的 XmlSchemaSet。
CodeCompileUnit是 .NET Framework 程式代碼文件物件模型 (CodeDOM) 的一部分,以抽象的方式表示 .NET Framework 程式代碼。 若要從 CodeCompileUnit產生實際程式代碼,請使用 類別的 CodeDomProvider 子類別,例如 CSharpCodeProvider 或 VBCodeProvider 類別。
匯入架構
創建XsdDataContractImporter的實例。
選擇性。 在建構函式中傳遞
CodeCompileUnit。 架構匯入期間產生的型別會新增至這個CodeCompileUnit實例,而不是從空白CodeCompileUnit開始。選擇性。 呼叫其中 CanImport 一個方法。 方法會判斷指定的架構是否為有效的數據合約架構,而且可以匯入。 方法
CanImport具有與Import(下一個步驟) 相同的多載。呼叫其中一個多載
Import方法,例如 Import(XmlSchemaSet) 方法。最簡單的多載會採用
XmlSchemaSet並匯入所有類型,包括在該架構集合中找到的匿名型別。 其他多載可讓您指定要匯入的 XSD 類型或型別清單(以 XmlQualifiedName 或XmlQualifiedName物件的集合形式)。 在此情況下,只會匯入指定的型別。 多載會使用 XmlSchemaElement 從XmlSchemaSet匯入特定元素,並且處理其相關聯的型別(無論是否為匿名型別)。 這個多載會傳回XmlQualifiedName,代表為這個元素所產生型別的資料契約名稱。若多次呼叫
Import方法,則會將多個項目新增至相同的CodeCompileUnit。 如果類型已經存在於CodeCompileUnit中,則不會生成。 在同一Import個 物件上多次呼叫XsdDataContractImporter,而不是使用多個XsdDataContractImporter物件。 這是避免產生重複類型的建議方式。備註
如果匯入期間發生失敗,
CodeCompileUnit將處於無法預測的狀態。 使用因匯入失敗而產生的CodeCompileUnit,可能會讓您面臨安全漏洞風險。您可以透過
CodeCompileUnit屬性存取 CodeCompileUnit。
匯入選項:自定義產生的類型
您可以將 Options 的屬性設定為 XsdDataContractImporter 類別的實例,以控制匯入過程中的各個方面。 許多選項會直接影響產生的類型。
控制存取層級(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 開關)
這對應工具中的 /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開關。
有時候,從架構產生的型別對於使用 .NET Framework 運行時間串行化引擎而言很重要。 在使用 .NET Framework 的類型進行遠端處理時,這個功能很有用。 若要啟用此功能,除了一般屬性之外,您還必須將 SerializableAttribute 屬性套用至產生的型別 DataContractAttribute 。 如果 GenerateSerializable 匯入選項設定為 true,則會自動產生 屬性。
下列範例顯示使用 Vehicle 匯入選項設定為 GenerateSerializable 所產生的 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
新增資料繫結支援(EnableDataBinding 或 /enableDataBinding 開關)
這會對應至 Svcutil.exe 工具上的 /enableDataBinding 開關。
有時候,您可能想要將架構產生的類型系結至圖形使用者介面元件,讓這些類型的實例的任何更新都會自動更新UI。
XsdDataContractImporter可以產生用來實作INotifyPropertyChanged介面的類型,讓任何屬性變更都會觸發事件。 如果您要產生類型以搭配支援此介面的用戶端 UI 程式設計環境使用(例如 Windows Presentation Foundation (WPF),請將 屬性EnableDataBinding設定true為 以啟用此功能。
下列範例顯示設定Vehicle為EnableDataBinding時所產生的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
匯入選項:選擇集合類型
XML 中的兩個特殊模式代表專案的集合:專案清單,以及一個專案與另一個專案之間的關聯。 以下是字串清單的範例。
<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>
備註
任何關聯也可以視為清單。 例如,您可以將上述關聯視為有兩個字段的複雜物件清單 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
您可以自定義針對這類架構模式產生的集合類型。 例如,您可能會想要產生衍生自 BindingList<T> 而非 List<T> 類別的集合,以便將類型系結至清單框,並在集合的內容變更時自動更新。 若要這樣做,請將 ReferencedCollectionTypes 類別的 ImportOptions 屬性設定為要使用的集合類型清單(以下稱為參考型別)。 匯入任何集合時,會掃描此參考集合類型清單,並在找到集合時使用最相符的集合。 關聯只會與實作泛型或非泛型 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 類型,而不是為每個服務產生新的類型。
若要這樣做,請將您想要重複使用的 .NET Framework 類型清單傳遞到ReferencedTypes類別上的ImportOptions屬性集合中。 如果上述任何類型都有符合架構類型名稱和命名空間的數據合約名稱和命名空間,則會執行結構比較。 如果判斷類型同時具有相符的名稱和比對結構,則會重複使用現有的 .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 類別。
即使 XsdDataContractImporter 屬性設定為 ImportXmlType,某些架構建構也無法
true匯入。 同樣地,請考慮針對這類情況使用 XmlSerializer 。在 ImportXmlType 是
true或false時,兩者都支援的確切架構建構描述在數據合約架構參考中。匯入和導出時,IXmlSerializable 型別的產生架構不會保留完整性。 也就是說,從產生的型別匯出架構,並匯入為類別並不會傳回原始架構。
可以結合 ImportXmlType 選項與 ReferencedTypes 先前所述的選項。 對於必須產生為 IXmlSerializable 實作的類型,使用 ReferencedTypes 功能時會略過結構檢查。
選項 ImportXmlType 會對應至 Svcutil.exe 工具上的 /importXmlTypes 選項。
使用產生的 IXmlSerializable 類別
產生的 IXmlSerializable 類型包含名為 「nodesField」 的私人字段,其會傳回物件的陣列 XmlNode 。 還原串行化這類類型的實例時,您可以使用 XML 檔物件模型,直接透過此欄位存取 XML 資料。 串行化此類型的實例時,您可以將此欄位設定為所需的 XML 資料,並將它串行化。
這可透過 IXmlSerializable 實作來完成。 在生成的 IXmlSerializable 類型中,ReadXml 實作會呼叫 ReadNodes 類別的 XmlSerializableServices 方法。 方法是輔助方法,可將透過XmlReader提供的 XML 轉換為XmlNode物件的陣列。 實作 WriteXml 則相反地將 XmlNode 物件的陣列轉換成一連串的 XmlWriter 呼叫。 這是使用WriteNodes方法完成的。
可以在產生的 IXmlSerializable 類別上執行架構匯出程式。 如先前所述,您將不會傳回原始架構。 相反地,您會獲得「anyType」這一 XSD 標準類型,作為任何 XSD 類型的通配符。
這可藉由將 XmlSchemaProviderAttribute 屬性套用至產生的 IXmlSerializable 類別,並指定呼叫 方法以產生 “anyType” 類型的方法 AddDefaultSchema 來完成。
備註
此 XmlSerializableServices 類型只存在以支援這個特定功能。 不建議用於任何其他用途。
匯入選項:進階選項
以下是進階匯入選項:
CodeProvider 屬性。 指定要使用來為生成的類別產生程式碼的CodeDomProvider。 匯入機制嘗試避免使用CodeDomProvider不支援的功能。 CodeProvider如果未設定 ,則會使用一組完整的 .NET Framework 功能,但沒有任何限制。
DataContractSurrogate 屬性。 您可以使用這個屬性來指定實 IDataContractSurrogate 作。 能夠 IDataContractSurrogate 客製化匯入過程。 如需詳細資訊,請參閱 資料合約代理。 根據預設,不會使用 Surrogate。