共用方式為


資料合約版本控制

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

中斷與不中斷變更的比較

資料合約的變更可以採用中斷或不中斷的方式進行。當資料合約以不中斷的方式變更時,使用舊版合約的應用程式可以與使用新版合約的應用程式通訊,而使用新版合約的應用程式可以與使用舊版合約的應用程式通訊。相反的,中斷變更則會阻止單向或雙向的通訊。

任何對類型的變更若不會影響其傳輸和接收的方式,則都是不中斷的變更。此類的變更並不會改變資料合約,只會改變基礎型別。例如,如果您接著將 DataMemberAttributeName 屬性設定為舊版的名稱,則您就可以使用不中斷方式變更欄位的名稱。下列程式碼說明資料合約的第 1 版。

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

下列程式碼示範不中斷變更。

' 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 
// 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;
}

某些變更會修改傳輸的資料,但可能會、也可能不會中斷。下列的變更則一定會中斷:

  • 變更資料合約的 NameNamespace 值。

  • 使用 DataMemberAttributeOrder 屬性變更資料成員的順序。

  • 重新命名資料成員。

  • 變更資料成員的資料合約。例如,將資料成員的型別從整數變更為字串,或從具有名為 "Customer" 資料合約的型別變更成具有名為 "Person" 資料合約的型別。

以下變更是允許的。

新增及移除資料成員

大部份的情況下,新增或移除資料成員不是採用中斷變更的方式,除非您要求嚴格的結構描述有效性 (根據舊結構描述驗證新執行個體)。

在將具有額外欄位的類型還原序列化為具有缺少欄位的類型時,則會忽略額外的資訊(為供周遊所需,您也可以儲存這些資訊。如需詳細資訊,請參閱向前相容資料合約)。

在將缺少欄位的類型還原序列化為具有額外欄位的類型時,額外欄位會保留其預設值,通常為零或 null(預設值可能會變更。如需詳細資訊,請參閱版本相容序列化回呼)。

例如,您可以在用戶端上使用 CarV1 類別,並在服務上使用 CarV2 類別,或者可以在服務上使用 CarV1 類別,而在用戶端上使用 CarV2 類別。

' 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 
// 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;
}

第 2 版的端點可以成功地將資料傳送至第 1 版的端點。序列化第 2 版的 Car 資料合約,會產生與下列類似的 XML。

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

第 1 版上的還原序列化引擎找不到與 HorsePower 欄位相符的資料成員,然後便捨棄該資料。

同時,第 1 版的端點可以將資料傳送至第 2 版的端點。序列化第 1 版的 Car 資料合約,會產生與下列類似的 XML。

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

因為傳入的 XML 未包含符合的資料,因此第 2 版的還原序列化程式不知道要將 HorsePower 欄位設定為什麼。相反的,該欄位會設為預設值 0。

必要的資料成員

DataMemberAttributeIsRequired 屬性設定為 true,即可將資料成員標記為必要項。如果在還原序列化時遺失了必要的資料,則會擲回例外狀況,而不是將該資料成員設定為預設值。

新增必要的資料成員是一種中斷變更。也就是,較新的類型仍舊可以傳送至使用舊類型的端點,而不是將較舊的類型傳送至使用新類型的端點。將任何舊版內已標記為必要項之資料成員移除,也是一種中斷變更。

IsRequired 屬性從 true 變更為 false 的動作是不中斷變更,但是將其從 false 變更為 true 的動作則可能會是中斷變更 (如果任何舊版的類型未含有所討論的資料成員)。

ms731138.note(zh-tw,VS.100).gif注意:
雖然將 IsRequired 屬性設定為 true,但傳入的資料可能會為 null 或零,而您必須準備一個類型來處理這種可能性。請勿使用 IsRequired 做為防止傳入資料損壞的安全性機制。

省略的預設值

您也可以根據 資料成員預設值 所述,將 DataMemberAttribute 屬性 (Attribute) 上的 EmitDefaultValue 屬性 (Property) 設為 false,但是不建議這麼做。如果這個設定為 false,則如果資料成員設定為預設值 (通常為 null 或零),將不會予以省略。在以下兩方面,這會與不同版本中之必要資料成員不相容:

  • 在某個版本內要求具有資料成員的資料合約,無法從不同版本 (其 EmitDefaultValue 設定為 false) 接收預設 (null 或零) 資料。

  • 具有 EmitDefaultValue 設定為 false 的必要資料成員,無法用來序列化其預設值 (null 或零),但是可以在還原序列化時接收此類的值。如此會產生反覆存取的問題 (可以讀入資料,但卻無法接著將相同的資料寫出)。因此,如果在某個版本內,IsRequiredtrue,且 EmitDefaultValuefalse,則相同的組合應套用至所有其他版本,此類沒有資料合約的版本將能夠產生不會導致反覆存取的值。

結構描述的考量

如需資料合約類型會產生哪些結構描述的說明,請參閱資料合約結構描述參考

為資料合約類型產生的結構描述 WCF 不提供版本控制。也就是說,從某些類型的版本所匯出的結構描述,只會包含該版本內存在的資料成員。實作 IExtensibleDataObject 介面不會變更類型的結構描述。

匯出至結構描述的資料成員,預設會做為選擇性項目。亦即,minOccurs (XML 屬性) 值設定為 0。必要的資料成員會以設定為 1 的 minOccurs 匯出。

如果要求嚴格遵循結構描述,則許多被視為是不中斷的變更實際上是中斷變更。在上述範例中,只具有 Model 項目的 CarV1 執行個體會根據 CarV2 結構描述 (即具有 ModelHorsepower 兩者,但兩者皆是選用項目) 進行驗證。不過,反向並不成立:CarV2 執行個體根據 CarV1 結構描述所進行的驗證則可能會失敗。

反覆存取還需要一些額外的考量。如需詳細資訊,請參閱向前相容資料合約內「結構描述的考量」一節。

其他允許的變更

實作 IExtensibleDataObject 介面為不中斷變更。不過,實作 IExtensibleDataObject 的版本之前的類型版本,並不存在反覆存取支援。如需詳細資訊,請參閱 向前相容資料合約.

列舉

加入或移除列舉型別成員是中斷變更。除非其合約名稱保持為與舊版中使用 EnumMemberAtttribute 屬性的名稱相同,否則變更列舉型別成員的名稱是中斷變更。如需詳細資訊,請參閱 資料合約中的列舉型別.

集合

大多數的集合變更是不中斷的,因為大部分的集合類型可以在資料合約模型內互相交換。不過,將非自訂的集合進行自訂 (反之亦然) 則是中斷變更。同時,變更集合的自訂設定是中斷變更,也就是,變更其資料合約名稱和命名空間、重複項目名稱、主要項目名稱,以及值項目名稱。如需詳細資訊集合自訂的詳細資訊,請參閱資料合約中的集合型別

當然,變更集合之內容的資料合約 (例如,從整數的清單變更為字串的清單) 是中斷變更。

另請參閱

參考

Name
DataMemberAttribute
Name
Namespace
Order
IsRequired
SerializationException
IExtensibleDataObject

概念

版本相容序列化回呼
最佳做法:資料合約版本控制
使用資料合約
資料合約等價
向前相容資料合約