共用方式為


最佳做法:數據合約版本控制

本主題列出建立數據合約的最佳做法,這些合約可在一段時間內輕鬆演進。 如需數據合約的詳細資訊,請參閱 使用數據合約中的主題。

架構驗證注意事項

在討論數據合約版本控制時,請務必注意,Windows Communication Foundation (WCF) 所匯出的數據合約架構沒有任何版本控制支援,除了元素默認標示為選擇性的事實之外。

這表示即使是最常見的版本設定案例,例如新增數據成員,也無法以與指定架構順暢的方式實作。 較新版本的數據合約(例如,新數據成員)不會使用舊架構進行驗證。

不過,有許多案例不需要嚴格的架構合規性。 許多 Web 服務平臺,包括使用 ASP.NET 建立的 WCF 和 XML Web 服務,預設不會執行架構驗證,因此容許架構未描述的額外元素。 使用這類平臺時,許多版本設定案例更容易實作。

因此,有兩套數據合約版本控制指導原則:一套適用於嚴格架構有效性很重要的情境,另一套適用於架構有效性不那麼重要的情境。

需要架構驗證時的版本設定

如果所有方向都需要嚴格的架構有效性(新到舊和舊對新),則數據合約應視為不可變。 如果需要版本控制,應該以不同的名稱或命名空間建立新的數據合約,並使用數據類型的服務合約應該據此進行版本設定。

例如,一個名為 PoProcessing 並包含 PostPurchaseOrder 作業的採購單處理服務合約會採用符合 PurchaseOrder 數據合約的參數。 PurchaseOrder如果合約必須變更,您必須建立新的數據合約,也就是 ,PurchaseOrder2其中包含變更。 您接著必須在服務合約層級處理版本設定。 例如,藉由建立採用PostPurchaseOrder2參數的PurchaseOrder2作業,或建立一個服務合約,其中PoProcessing2作業使用PostPurchaseOrder數據合約PurchaseOrder2

請注意,其他數據合約所參考的數據合約變更也會延伸至服務模型層。 例如,在上一個案例中, PurchaseOrder 數據合約不需要變更。 不過,它包含數據合約的數據成員 Customer ,而數據合約又包含需要變更的數據合約數據成員 Address 。 在此情況下,您必須建立 Address2 具有所需變更的數據合約、 Customer2 包含 Address2 數據成員的數據合約,以及 PurchaseOrder2 包含 Customer2 數據成員的數據合約。 如同先前的情況,服務合約也必須進行版本設定。

雖然在這些範例中名稱被更改(透過加上「2」),但建議改變命名空間而不是直接改變名稱,方法是附加帶有版本號碼或日期的新命名空間。 例如, http://schemas.contoso.com/2005/05/21/PurchaseOrder 數據合約會變更為 http://schemas.contoso.com/2005/10/14/PurchaseOrder 數據合約。

如需詳細資訊,請參閱最佳做法: 服務版本控制

有時候,您必須保證應用程式所傳送訊息的嚴格架構合規性,但無法依賴傳入訊息嚴格符合架構規範。 在此情況下,傳入訊息可能會包含多餘的數據。 WCF 會儲存和傳回多餘的值,因而導致傳送架構無效的訊息。 若要避免這個問題,應該關閉來回功能。 做法有二種。

如需有關來回處理的詳細資訊,請參閱 Forward-Compatible 數據合約

不需要架構驗證時的版本設定

很少需要嚴格的架構合規性。 許多平臺容許架構未描述的額外元素。 只要容許這一點,就可以使用 數據合約版本設定Forward-Compatible 數據合約 中所述的完整功能集。 建議使用下列指導方針。

某些指導方針必須嚴格遵循,才能在預期接收舊版的情況下傳送新版本,或在預期接收新版的情況下傳送舊版。 其他指導方針並非絕對必要,但會列在這裡,因為它們可能會受到架構版本設定的未來影響。

  1. 請勿嘗試依類型繼承來建立數據合約的版本。 若要建立較新版本,請變更現有類型上的數據合約,或建立新的不相關類型。

  2. 允許將繼承與數據合約一起使用,前提是繼承不會當做版本設定機制使用,而且會遵循特定規則。 如果類型衍生自特定基底類型,請勿讓它在未來版本中衍生自不同的基底類型(除非它有相同的數據合約)。 有一個例外狀況:您可以在數據合約類型與其基底類型之間,將類型插入階層中,但前提是它不包含與階層中其他類型任何可能版本相同名稱的數據成員。 一般而言,在相同繼承階層的不同層級使用具有相同名稱的數據成員可能會導致嚴重的版本設定問題,並應避免。

  3. 從數據合約的第一個版本開始,務必實施 IExtensibleDataObject 來實現雙向數據交換。 如需詳細資訊,請參閱 Forward-Compatible 數據合約。 如果您已發行一或多個版本的類型,而不實作這個介面,請在類型的下一個版本中實作它。

  4. 在更新版本中,請勿變更數據合約名稱或命名空間。 如果變更數據合約基礎類型的名稱或命名空間,請務必使用適當的機制來保留數據合約名稱和命名空間,例如 NameDataContractAttribute屬性。 如需命名的詳細資訊,請參閱 數據合約名稱

  5. 在更新版本中,請勿變更任何數據成員的名稱。 如果變更數據成員之欄位、屬性或事件的名稱,請使用 NameDataMemberAttribute 屬性來保留現有的數據成員名稱。

  6. 在更新版本中,請勿變更數據成員的任何欄位、屬性或事件類型,使該數據成員產生的數據合約變更。 請記住,為了確定預期的資料合約,介面類型等同於 Object

  7. 在更新版本中,請勿藉由調整 Order 屬性的 DataMemberAttribute 屬性來變更現有數據成員的順序。

  8. 在更新版本中,可以新增新的數據成員。 它們應該一律遵循下列規則:

    1. 屬性 IsRequired 應該一律保留在其預設值 false

    2. 如果成員的 null 預設值為 或零是無法接受的,則應該使用 OnDeserializingAttribute 提供回呼方法,以提供合理的預設值,以防成員不存在於傳入數據流中。 如需回呼的詳細資訊,請參閱 Version-Tolerant 串行化回呼

    3. DataMemberAttribute.Order屬性應該用來確定所有新增的數據成員都會出現在現有的數據成員之後。 建議的做法如下:第一版數據合約中的數據成員不應設定其 Order 屬性。 數據合約第 2 版中新增的所有資料成員都應該將其 Order 屬性設定為 2。 在資料合約第 3 版中新增的所有資料成員都應該將其屬性設置為 3,依此類推。 允許將多個數據成員設定為相同的 Order 數位。

  9. 請勿在更新版本中移除數據成員,即使 IsRequired 屬性在舊版的預設屬性 false 上保留。

  10. 請勿在任何現有數據成員上從版本到版本變更IsRequired屬性。

  11. 針對必要的數據成員(其中 IsRequiredtrue),請勿將 EmitDefaultValue 屬性從版本變更為版本。

  12. 請勿嘗試建立分支版本控制階層。 也就是說,至少應該有一條路徑,從任何版本通往其他任一版本,且僅使用這些指導方針所允許的變更。

    例如,如果 Person 數據合約第 1 版只包含 Name 數據成員,則不應該建立合約第 2a 版,只新增 Age 成員,而第 2b 版僅新增 Address 成員。 從 2a 到 2b 將涉及移除年齡並新增地址;往另一個方向將需要移除地址並新增年齡。 這些指導方針不允許移除成員。

  13. 您通常不應該在新版本的應用程式中建立現有數據合約類型的新子類型。 同樣地,您不應該建立新的數據合約,以取代宣告為 Object 或介面類型的數據成員。 只有在您知道您可以將新類型新增至舊應用程式所有實例的已知類型清單時,才允許建立這些新類別。 例如,在您應用程式的第 1 版中,您可能擁有名為 LibraryItem 的資料合約類型,以及 Book 和 Newspaper 的資料合約子類型。 LibraryItem 接著會有包含書籍和報紙的已知類型清單。 假設您現在在 2 版中新增 Magazine 類型,這是 LibraryItem 的子類型。 如果您將Magazine實例從第2版傳送至第1版,由於在已知類型清單中找不到Magazine資料契約,將會擲回例外狀況。

  14. 您不應該在版本之間新增或移除列舉成員。 除非您在 EnumMemberAttribute 屬性上使用 Name 屬性來保留資料合約模型中的名稱,否則您不應重新命名枚舉成員。

  15. 集合可在數據合約模型中交換,如 數據合約中的集合類型中所述。 這可讓您有極大的彈性。 不過,請確定您不會不小心以不可替換的方式,將集合類型從一個版本更改為另一個版本。 例如,請勿從非自定義集合(也就是不含 CollectionDataContractAttribute 屬性)變更為自定義集合,或將自定義集合變更為非自定義集合。 此外,請勿在不同版本中更改CollectionDataContractAttribute的屬性。 唯一允許的變更是,如果基礎集合類型的名稱或命名空間已變更,而且您必須使其數據合約名稱和命名空間與上一個版本相同,則唯一允許的變更是新增 Name 或 Namespace 屬性。

當特殊情況適用時,可以安全地忽略此處所列的一些指導方針。 在偏離指導方針之前,請確定您完全瞭解相關的串行化、還原串行化和架構機制。

另請參閱