次の方法で共有


ベスト プラクティス: データ コントラクトのバージョン管理

このトピックでは、時間の経過と同時に簡単に進化できるデータ コントラクトを作成するためのベスト プラクティスを示します。 データ コントラクトの詳細については、「データ コントラクトの使用」のトピックを 参照してください。

スキーマ検証に関する注意事項

データ コントラクトのバージョン管理について説明する際には、Windows Communication Foundation (WCF) によってエクスポートされるデータ コントラクト スキーマにはバージョン管理のサポートがないため、要素が既定で省略可能としてマークされている点に注意することが重要です。

つまり、新しいデータ メンバーの追加など、最も一般的なバージョン管理シナリオであっても、特定のスキーマに関してシームレスな方法で実装することはできません。 データ コントラクトの新しいバージョン (たとえば、新しいデータ メンバーを含む) は、古いスキーマを使用して検証しません。

ただし、スキーマの厳密なコンプライアンスが必要ないシナリオは多数あります。 ASP.NET を使用して作成された WCF および XML Web サービスを含む多くの Web サービス プラットフォームでは、既定ではスキーマ検証が実行されないため、スキーマで記述されていない追加の要素が許容されます。 このようなプラットフォームを使用する場合、多くのバージョン管理シナリオを実装する方が簡単です。

したがって、データ コントラクトのバージョン管理ガイドラインには、厳密なスキーマの有効性が重要なシナリオ用と、そうでない場合のシナリオ用のセットの 2 つのセットがあります。

スキーマ検証が必要な場合のバージョン管理

すべての方向で厳密なスキーマの有効性が必要な場合 (新旧および古いから新しい)、データ コントラクトは不変と見なす必要があります。 バージョン管理が必要な場合は、別の名前または名前空間で新しいデータ コントラクトを作成し、それに応じてデータ型を使用するサービス コントラクトをバージョン管理する必要があります。

たとえば、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 によって格納および返されるため、スキーマが無効なメッセージが送信されます。 この問題を回避するには、ラウンドトリップ機能をオフにする必要があります。 これを行うには 2 つの方法があります。

ラウンドトリップの詳細については、「 Forward-Compatible データ コントラクト」を参照してください。

スキーマ検証が必要ない場合のバージョン管理

スキーマの厳密なコンプライアンスはほとんど必要ありません。 多くのプラットフォームでは、スキーマで記述されていない追加の要素が許容されます。 これが許容される限り、 データ コントラクトのバージョン管理とデータ コントラクトForward-Compatible で説明されている機能の完全なセットを使用できます。 次のガイドラインをお勧めします。

古いバージョンが想定されている型の新しいバージョンを送信したり、新しいバージョンが予想される古いバージョンを送信したりするには、一部のガイドラインに正確に従う必要があります。 他のガイドラインは厳密には必須ではありませんが、スキーマのバージョン管理の将来の影響を受ける可能性があるため、ここに記載されています。

  1. 型の継承によってデータ コントラクトのバージョンを設定しないでください。 新しいバージョンを作成するには、既存の型のデータ コントラクトを変更するか、関連付けられていない新しい型を作成します。

  2. 継承をバージョン管理メカニズムとして使用せず、特定の規則に従っている場合は、継承をデータ コントラクトと共に使用できます。 型が特定の基本型から派生する場合は、将来のバージョンで別の基本型から派生させないでください (同じデータ コントラクトがない限り)。 これには 1 つの例外があります。データ コントラクト型とその基本型の間の階層に型を挿入できますが、階層内の他の型の使用可能なバージョンの他のメンバーと同じ名前のデータ メンバーが含まれていない場合に限ります。 一般に、同じ継承階層の異なるレベルで同じ名前のデータ メンバーを使用すると、深刻なバージョン管理の問題につながる可能性があり、回避する必要があります。

  3. データ コントラクトの最初のバージョン以降では、ラウンドトリップを有効にするために常に IExtensibleDataObject を実装します。 詳細については、「 Forward-Compatible データ コントラクト」を参照してください。 このインターフェイスを実装せずに型の 1 つ以上のバージョンをリリースした場合は、型の次のバージョンで実装します。

  4. 以降のバージョンでは、データ コントラクト名または名前空間を変更しないでください。 データ コントラクトの基になる型の名前または名前空間を変更する場合は、NameDataContractAttribute プロパティなどの適切なメカニズムを使用して、データ コントラクトの名前と名前空間を保持してください。 名前付けの詳細については、「 データ コントラクト名」を参照してください。

  5. 以降のバージョンでは、データ メンバーの名前を変更しないでください。 データ メンバーの基になるフィールド、プロパティ、またはイベントの名前を変更する場合は、NameDataMemberAttribute プロパティを使用して、既存のデータ メンバー名を保持します。

  6. 以降のバージョンでは、データ メンバーの結果のデータ コントラクトが変更されるように、データ メンバーの基になるフィールド、プロパティ、またはイベントの型を変更しないでください。 インターフェイスの型は、予想されるデータ コントラクトを決定する目的で Object に相当することに注意してください。

  7. 以降のバージョンでは、Order属性の DataMemberAttribute プロパティを調整して、既存のデータ メンバーの順序を変更しないでください。

  8. 新しいバージョンでは、新しいデータ メンバーを追加できます。 常に次の規則に従う必要があります。

    1. IsRequired プロパティは常に既定値の false のままにする必要があります。

    2. メンバーの既定値 null または 0 が許容できない場合は、受信ストリームにメンバーが存在しない場合に適切な既定値を提供するために、 OnDeserializingAttribute を使用してコールバック メソッドを指定する必要があります。 コールバックの詳細については、「 Version-Tolerant シリアル化コールバック」を参照してください。

    3. DataMemberAttribute.Order プロパティを使用して、新しく追加されたすべてのデータ メンバーが既存のデータ メンバーの後に表示されるようにする必要があります。 これを行うための推奨される方法は次のとおりです。データ コントラクトの最初のバージョンのデータ メンバーに、 Order プロパティを設定する必要はありません。 データ コントラクトのバージョン 2 で追加されるすべてのデータ メンバーには、 Order プロパティが 2 に設定されている必要があります。 データ コントラクトのバージョン 3 で追加されるすべてのデータ メンバーには、 Order が 3 に設定されている必要があります。 複数のデータ メンバーを同じ Order 番号に設定することは許容されます。

  9. IsRequired プロパティが以前のバージョンのfalseの既定のプロパティに残っている場合でも、以降のバージョンのデータ メンバーを削除しないでください。

  10. 既存のデータ メンバーの IsRequired プロパティをバージョンからバージョンに変更しないでください。

  11. 必要なデータ メンバー ( IsRequiredtrue) の場合は、 EmitDefaultValue プロパティをバージョンからバージョンに変更しないでください。

  12. 分岐バージョン管理階層を作成しないでください。 つまり、これらのガイドラインで許可されている変更のみを使用して、任意のバージョンから他のバージョンへの少なくとも 1 つの方向のパスが常に存在する必要があります。

    たとえば、Person データ コントラクトのバージョン 1 に Name データ メンバーのみが含まれている場合は、Age メンバーのみを追加するコントラクトのバージョン 2a と Address メンバーのみを追加するバージョン 2b を作成しないでください。 2aから2bに行くには、年齢を削除し、アドレスを追加する必要があります。他の方向に進むには、Address を削除して Age を追加する必要があります。 これらのガイドラインでは、メンバーの削除は許可されていません。

  13. 通常、アプリケーションの新しいバージョンでは、既存のデータ コントラクト型の新しいサブタイプを作成しないでください。 同様に、Object またはインターフェイス型として宣言されたデータ メンバーの代わりに使用される新しいデータ コントラクトを作成しないでください。 これらの新しいクラスの作成は、古いアプリケーションのすべてのインスタンスの既知の型リストに新しい型を追加できることがわかっている場合にのみ許可されます。 たとえば、アプリケーションのバージョン 1 では、Book と Newspaper のデータ コントラクト サブタイプを持つ LibraryItem データ コントラクト型を使用できます。 LibraryItem には、Book と Newspaper を含む既知の型リストが含まれます。 次に、LibraryItem のサブタイプであるマガジンの種類をバージョン 2 に追加したとします。 Magazine インスタンスをバージョン 2 からバージョン 1 に送信した場合、Magazine データ コントラクトは既知の型の一覧に見つからず、例外がスローされます。

  14. バージョン間で列挙メンバーを追加または削除しないでください。 また、 EnumMemberAttribute 属性の Name プロパティを使用してデータ コントラクト モデル内の名前を同じに保つ場合を除き、列挙メンバーの名前を変更しないでください。

  15. コレクションは、「データ コントラクトのコレクション型」の説明に従って 、データ コントラクト モデルで交換可能です。 これにより、優れた柔軟性を実現できます。 ただし、互換性のない方法でコレクションの種類を誤ってバージョンからバージョンに変更しないようにしてください。 たとえば、カスタマイズされていないコレクション (つまり、 CollectionDataContractAttribute 属性を持たない) からカスタマイズされたコレクションやカスタマイズされたコレクションからカスタマイズされていないコレクションに変更しないでください。 また、 CollectionDataContractAttribute のプロパティをバージョンからバージョンに変更しないでください。 基になるコレクション型の名前または名前空間が変更され、そのデータ コントラクト名と名前空間を以前のバージョンと同じにする必要がある場合、唯一の変更は Name または Namespace プロパティの追加です。

特別な状況が該当する場合、ここに記載されているガイドラインの一部は無視しても問題ありません。 ガイドラインから逸脱する前に、関連するシリアル化、逆シリアル化、スキーマのメカニズムを十分に理解しておいてください。

こちらも参照ください