共用方式為


數據合約版本控制

隨著應用程式的發展,您可能也必須變更服務使用的數據合約。 本主題說明如何版本化資料合約。 本主題描述數據合約版本設定機制。 如需完整的概觀和規範版本控制指引,請參閱 最佳做法:數據合約版本控制

重大變更與非重大變更

數據合約的變更可能會造成中斷或不會中斷。 以非中斷方式變更數據合約時,使用舊版合約的應用程式可以使用較新版本與應用程式通訊,而使用較新版本合約的應用程式可以使用較舊版本與應用程式通訊。 另一方面,重大變更可能阻礙單一或雙向通訊。

對類型進行的不影響其傳輸和接收方式的任何變更都不會造成中斷。 這類變更不會變更數據合約,只有基礎類型。 例如,您可以變更欄位名稱而不會中斷,方法是將NameDataMemberAttribute屬性設定為舊版名稱。 下列程式代碼顯示數據合約的第1版。

// Version 1
[DataContract]
public class Person
{
    [DataMember]
    private string Phone;
}
' Version 1
<DataContract()> _
Public Class Person
    <DataMember()> _
    Private Phone As String
End Class

下列程式代碼顯示非中斷性變更。

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

某些變更會修改傳輸的數據,但不一定會造成破壞性變更。 下列變更會導致中斷:

  • 變更資料合約中 NameNamespace 的值。

  • 使用 OrderDataMemberAttribute屬性來變更數據成員的順序。

  • 重新命名數據成員。

  • 變更資料成員的資料契約。 例如,將數據成員的類型從整數變更為字串,或從具有名為 「Customer」 之數據合約的類型變更為名為 「Person」 的數據合約類型。

您也可以進行下列變更。

新增和移除數據成員

在大部分情況下,新增或移除數據成員不是重大變更,除非您需要嚴格的架構有效性(針對舊架構驗證的新實例)。

當具有額外欄位的類型還原串行化為遺漏字段的類型時,會忽略額外的資訊。 (也可能儲存用於往返目的;如需詳細資訊,請參閱 Forward-Compatible 數據合約)。

當遺漏欄位的類型還原串行化為具有額外欄位的類型時,額外的欄位會保留在其預設值,通常是零或 null。 (可能會變更預設值;如需詳細資訊,請參閱 Version-Tolerant 串行化回呼。)

例如,您可以在 CarV1 用戶端上使用 類別,以及在 CarV2 服務上使用 類別,也可以在 CarV1 服務上使用 類別,以及在 CarV2 用戶端上使用 類別。

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

第 2 版端點可以成功將數據傳送至第 1 版端點。 串行化數據合約第 2 Car 版會產生類似下列的 XML。

<Car>  
    <Model>Porsche</Model>  
    <HorsePower>300</HorsePower>  
</Car>  

V1 上的反序列化引擎無法找到與 HorsePower 欄位相符的數據成員,因此捨棄該數據。

此外,第 1 版端點可以將數據傳送至第 2 版端點。 串行化數據合約第 1 版 Car 會產生類似下列的 XML。

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

版本 2 的去序列化器無法確定該將 HorsePower 欄位設定為什麼值,因為在傳入的 XML 中沒有相符的資料。 相反地,欄位會設定為預設值 0。

必要數據成員

將數據成員標示為必需,可以透過將IsRequiredDataMemberAttribute屬性設定為true來達成。 如果在反序列化時遺漏必要的數據,則會拋出例外,而不是將數據成員設定為其預設值。

新增必要的數據成員是重大變更。 也就是說,較新的類型仍可傳送至較舊類型的端點,但反過來就不行。 將任何早期版本中標記為必要的資料成員移除也是重大變更。

將屬性值從 IsRequired 變更為 true 不會中斷,但如果任何舊版的類型沒有相關的數據成員,那麼將其從 false 變更為 false 則可能會導致中斷。

備註

雖然 屬性 IsRequired 設定為 true,但傳入的數據可能是 Null 或零,而且類型必須準備好處理這種可能性。 請勿使用 IsRequired 做為安全性機制,以防止不正確的傳入數據。

省略的預設值

雖然不建議,但可以將 DataMemberAttribute 屬性的 EmitDefaultValue 屬性設定為 false,如 資料成員預設值中所述。 如果此設定為 false,則如果數據成員設定為預設值(通常是 null 或零),則不會發出該成員。 這在兩個方面與不同版本中必要的數據成員不相容:

  • 具有某個版本所需數據成員的數據合約,無法從數據成員設定 EmitDefaultValuefalse的不同版本接收預設(Null 或零)數據。

  • EmitDefaultValue 設定為 false 的必要資料成員無法用來序列化其預設(null 或零)值,但在反序列化時可以接收這類值。 這會產生資料往返問題(資料可以被讀入,但同樣的資料無法被寫出)。 因此,如果 IsRequiredtrue,而 EmitDefaultValuefalse 都在同一個版本下,則相同的組合應該適用於所有其他版本,以確保數據合約的任何版本都無法產生不會導致往返的值。

架構考慮

如需針對數據合約類型產生之架構的說明,請參閱 數據合約架構參考

WCF 為數據合約類型產生的架構未考慮版本控制。 也就是說,從特定類型版本導出的架構只包含該版本中存在的那些數據成員。 實作 IExtensibleDataObject 介面並不會變更型別的架構。

根據預設,數據成員會匯出至架構做為選擇性元素。 也就是說, minOccurs [XML 屬性] 值會設定為 0。 必要的數據成員會匯出,並將 minOccurs 設為 1。

如果需要嚴格遵循架構,則許多視為非中斷的變更實際上都會中斷。 在上述範例中,僅包含CarV1元素的Model實例會根據CarV2架構進行驗證(此架構包含Model元素和Horsepower元素,但這兩者都是選擇性的)。 不過,情況不相反:CarV2 實例不會通過 CarV1 結構的驗證。

來回行程也需要一些額外的考慮。 如需詳細資訊,請參閱 Forward-Compatible 數據合約 中的「架構注意事項」一節。

其他允許的變更

實作 IExtensibleDataObject 介面是一項非中斷性變更。 不過,在 IExtensibleDataObject 實作的版本之前,型別的版本並不存在回路支援。 如需詳細資訊,請參閱 Forward-Compatible 數據合約

列舉項目

新增或移除列舉成員是重大變更。 變更列舉成員的名稱會造成中斷,除非其合約名稱保留與舊版相同,只需使用EnumMemberAttribute屬性。 如需詳細資訊,請參閱 數據合約中的列舉型別

收藏品

大部分的集合變更都是非中斷的,因為大部分的集合類型在數據合約模型中彼此可互換。 然而,將非客製化集合體改為客製化或將客製化改為非客製化都是重大變更。 此外,變更集合的自定義設定是重大變更;也就是說,變更其數據合約名稱和命名空間、重複專案名稱、索引鍵專案名稱和值專案名稱。 如需集合自定義的詳細資訊,請參閱 數據合約中的集合類型
自然地,變更集合內容的數據合約(例如,從整數清單變更為字串清單)是重大變更。

另請參閱