SOA 系統中,服務與用戶端獨立演進是常態。資料合約 (Data Contract) 版本變更時,如何確保現有用戶端不中斷?本文透過實例探討 WCF 如何處理單方面新增資料成員的版本控制,以及解決往返問題的 IExtensibleDataObject 機制。
Artech.DataContractVersioning.Service,定義 Order 資料合約 (OrderID、OrderDate、SupplierID)。Artech.DataContractVersioning.Client,定義 CustomOrder,透過屬性對應服務端合約,並額外新增 ShippingAddress。
[DataContract(Namespace = "https://artech.datacontractversioning")]
public class Order
{
[DataMember(Order = 0)] public Guid OrderID { get; set; }
[DataMember(Order = 1)] public DateTime OrderDate { get; set; }
[DataMember(Order = 2)] public Guid SupplierID { get; set; }
}
[DataContract(Name = "Order", Namespace = "https://artech.datacontractversioning")]
public class CustomOrder
{
[DataMember(Order = 0, Name = "OrderID")] public Guid OrderNo { get; set; }
[DataMember(Order = 2, Name = "SupplierID")] public Guid SupplierNo { get; set; }
[DataMember(Order = 1)] public DateTime OrderDate { get; set; }
}
透過 Name、Namespace、Order 屬性,雙方 CLR 型別雖不同,但資料合約完全匹配。
用戶端在 CustomOrder 新增 ShippingAddress:
[DataMember(Order = 3)] public string ShippingAddress { get; set; }
呼叫服務端 Process(Order order) (直接回傳接收的 Order) 後,ShippingAddress 遺失:

原因:服務端 Order 無此成員,反序列化時忽略未知資料。若該物件再流向其他服務,將造成往返問題:資料在多跳傳遞中逐漸遺失擴充欄位。
在服務端 Order 實作 IExtensibleDataObject:
[DataContract(Namespace = "https://artech.datacontractversioning")]
public class Order : IExtensibleDataObject
{
[DataMember(Order = 0)] public Guid OrderID { get; set; }
[DataMember(Order = 1)] public DateTime OrderDate { get; set; }
[DataMember(Order = 2)] public Guid SupplierID { get; set; }
public ExtensionDataObject ExtensionData { get; set; }
}
IExtensibleDataObject 僅定義一個 ExtensionData 屬性 (型別 ExtensionDataObject),用於儲存反序列化時遇到的未識別資料。
再次執行用戶端,ShippingAddress 完整保留:

偵錯檢視 ExtensionData 內容,確認包含 ShippingAddress:

| 場景 | 未實作 IExtensibleDataObject | 實作 IExtensibleDataObject |
|---|---|---|
| 用戶端新增成員 | 服務端反序列化時捨棄 | 服務端保留於 ExtensionData |
| 服務端回傳物件 | 遺失擴充資料 | 原樣回傳擴充資料 |
| 多跳傳遞 (A→B→C) | 逐層遺失 | 完整保留 |
IExtensibleDataObject,確保向前相容。Order 屬性指定成員序列化順序,配合版本演進更穩健。DataMember,改為標記 IsRequired=false (預設) 並新增成員。WCF 透過 IExtensibleDataObject 优雅解決資料合約版本演進中的往返問題,是建構可長期演進 SOA 系統的關鍵機制。下一篇將探討集合與字典型別的資料合約支援。