Поделиться через


Рекомендации. Управление версиями контракта данных

В данном разделе приводятся рекомендации по созданию контрактов данных, которые можно легко развить со временем. Дополнительные сведения контрактам данных см. в подразделах раздела Использование контрактов данных.

Замечания по проверке схемы

При обсуждении управления версиями контрактов данных важно отметить, что схема контракта данных, экспортированная службой Windows Communication Foundation (WCF), не обеспечивает поддержку управления версиями, за исключением того, что элементы отмечаются как необязательные по умолчанию.

Это значит, что даже самые общие сценарии управления версиями, такие как добавление нового члена данных, невозможно реализовать так, чтобы обеспечить тесное взаимодействие с данной схемой. Новые версии контракта данных (например, с новым членом данных) не выполняют проверку с использованием старой схемы.

Однако существует много сценариев, в которых не требуется строгое соответствие схеме. Множество платформ веб-служб, включая WCF и веб-службы XML, созданные с использованием ASP.NET, не выполняют проверку схемы по умолчанию и, следовательно, допускают наличие дополнительных элементов, не описанных в схеме. При работе с такими платформами множество сценариев управления версиями легче реализовать.

Таким образом, предусмотрено два набора рекомендаций по управлению версиями контрактов данных: один набор для сценариев, в которых строгое соответствие схеме необходимо, и второй набор для сценариев, в которых нет необходимости в строгом соответствии схеме.

Управление версиями при необходимости в проверке схемы

Если строгое соответствие схеме является обязательным требованием во всех направлениях (от новой версии к старой и от старой версии к новой), контракты данных следует считать неизменяемыми. При необходимости в управлении версиями следует создать новый контракт данных с другим именем или пространством имен, и управление версиями контракта службы, использующего тип данных, должно осуществляться соответствующим образом.

Например, контракт службы обработки заказов на поставку с именем 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, что приводит к отправке сообщений с недействительной схемой. Чтобы избежать этой проблемы, необходимо выключить функцию полной совместимости версий. Это можно сделать двумя способами.

Дополнительные сведения полной совместимости версий см. в разделе Контракты данных, совместимые с любыми будущими изменениями.

Управление версиями при отсутствии необходимости в проверке схемы

Строгое соответствие схеме требуется редко. Множество платформ допускают наличие дополнительных элементов, не описанных в схеме. Пока наличие таких элементов допускается, можно использовать полный набор функций, описанных в разделах Управление версиями контракта данных и Контракты данных, совместимые с любыми будущими изменениями. Рекомендуется соблюдать следующее.

Некоторые рекомендации необходимо соблюдать строго, чтобы отправлять новые версии типа, если ожидается старая версия, или отправлять старую версию, если ожидается новая версия. Другие рекомендации не обязательно соблюдать строго, но они перечислены ниже, поскольку на них может повлиять будущее управление версиями схемы.

  1. Не пытайтесь управлять версиями контрактов данных с использованием наследования типов. Чтобы создать более поздние версии, либо измените контракт данных в существуем типе, либо создайте новый несвязанный тип.

  2. Использование наследования вместе с контрактами данных допускается, если наследование не используется как механизм управления версиями и выполняются определенные правила. Если тип наследуется от определенного базового типа, он не должен наследоваться от другого базового типа в будущей версии (за исключением случаев, когда у них одинаковые контракты данных). Существует одно исключение из этого: можно вставить тип в иерархию между типом контракта данных и его базовым типом, но только если в нем не содержится членов данных с такими же именами, как у других членов в любых возможных версиях других типов в иерархии. Как правило, использование членов данных с одинаковыми именами на разных уровнях одной и той же иерархии наследования может привести к серьезным проблемам с управлением версиями. Этого следует избегать.

  3. Начиная с первой версии контракта данных, всегда реализуйте IExtensibleDataObject для включения полной совместимости версий. Дополнительные сведения см. в разделе Контракты данных, совместимые с любыми будущими изменениями. Если имеется одна или несколько версий типа без реализации этого интерфейса, реализуйте его в следующей версии типа.

  4. В более поздних версиях не изменяйте имя или пространство имен контракта данных. При изменении имени или пространства имен базового типа контракта данных обязательно сохраните имя и пространство имен контракта данных с помощью соответствующих механизмов, таких как свойство Name атрибута DataContractAttribute. Дополнительные сведения именованию см. в разделе Имена контрактов данных.

  5. В более поздних версиях не изменяйте имена членов данных. При изменении имени поля, свойства или базового события члена данных используйте свойство Name атрибута DataMemberAttribute, чтобы сохранить существующее имя члена данных.

  6. В более поздних версиях не изменяйте тип поля, свойства или базового события члена данных, чтобы не изменился итоговый контракт данных для члена данных. Необходимо помнить, что типы интерфейсов эквивалентны классу Object, при определении ожидаемого контракта данных.

  7. В более поздних версиях не изменяйте порядок существующих членов данных путем изменения свойства Order атрибута DataMemberAttribute.

  8. В более поздних версиях можно добавлять новые члены данных. Они всегда должны соответствовать следующим правилам.

    1. Для свойства IsRequired всегда следует сохранять значение по умолчанию false.

    2. Если значение по умолчанию null или ноль для члена неприемлемо, необходимо предоставить метод обратного вызова с использованием атрибута OnDeserializingAttribute для обеспечения разумного значения по умолчанию при отсутствии члена во входящем потоке. Дополнительные сведения обратному вызову см. в разделе Обратные вызовы сериализации, независимые от версий.

    3. Свойство Order атрибута DataMemberAttribute необходимо использовать для гарантии того, что все только что добавленные члены данных отображаются после существующих членов данных. Рекомендуемый способ выполнения этого заключается в следующем: значение свойству Order не должно быть присвоено ни для одного члена данных в первой версии контракта данных. Для всех элементов данных, добавленных в версии 2 контракта данных, свойство Order должно иметь значение 2. Для всех элементов данных, добавленных в версии 3 контракта данных, свойство Order должно иметь значение 3 и так далее Допускается задание нескольких членов данных одному номеру свойства Order.

  9. Не удаляйте члены данных в более поздних версиях, даже если для свойства IsRequired сохранено значение по умолчанию false в предыдущих версиях.

  10. Не изменяйте свойство IsRequired существующих членов данных от версии к версии.

  11. Для требуемых членов данных (свойству IsRequired присвоено значение true) не изменяйте свойство EmitDefaultValue от версии к версии.

  12. Не пытайтесь создать ответвления иерархий управления версиями. Это значит, что всегда должен указываться путь, по крайней мере, в одном направлении от версии к версии, с использованием только тех изменений, которые допускаются этими правилами.

    Например, если в версии 1 контракта данных "Person" содержится только член данных "Name", не следует создавать версию 2a контракта, добавляя только член "Age", и версию 2b, добавляя только член "Address". Переход от версии 2a к версии 2b будет включать в себя удаление члена "Age" и добавление члена "Address". Переход в другом направлении повлечет за собой удаление члена "Address" и добавление члена"Age". Согласно этим правилам, удалять члены запрещается.

  13. Обычно не следует создавать новые подтипы существующих типов контрактов данных в новой версии приложения. Аналогично, не следует создавать новые контракты данных, используемые вместо членов данных, объявленных как "Object" или как типы интерфейса. Создание таких новых классов допускается, только если известно, что можно добавить новые типы в список известных типов всех экземпляров старого приложения. Например, в версии 1 приложения имеется тип контракта данных "LibraryItem" с подтипами контракта данных "Book" и "Newspaper". Тип "LibraryItem" будет иметь список известных типов, содержащий подтипы "Book" и "Newspaper". Предположим, в версию 2 добавляется тип "Magazine", являющийся подтипом типа "LibraryItem". При отправке экземпляра "Magazine" от версии 2 к версии 1 контракт данных "Magazine" невозможно найти в списке известных типов, и вызывается исключение.

  14. Не следует добавлять или удалять члены перечисления от версии к версии. Также не следует переименовывать члены перечисления, если не используется свойство "Name" атрибута EnumMemberAttribute, чтобы сохранить имена в модели контракта данных неизменными.

  15. Коллекции взаимозаменяемы в модели контракта данных, как описано в разделе Типы коллекций в контрактах данных. Это повышает степень гибкости. Однако убедитесь, что тип коллекции случайно не изменен невзаимоизменяемым способом от версии к версии. Например, не изменяйте ненастроенную коллекцию (т. е. без атрибута CollectionDataContractAttribute) на настроенную или настроенную коллекцию на ненастроенную. Кроме того, не изменяйте свойства атрибута CollectionDataContractAttribute от версии к версии. Единственным допустимым изменением является добавление свойства "Name" или "Namespace", если имя или пространство имен типа базовой коллекции были изменены, и необходимо, чтобы имя и пространство имен контракта данных были теми же, что и в предыдущей версии.

В особых обстоятельствах некоторые правила, указанные в данном разделе, можно проигнорировать. Убедитесь, что полностью понимаете принципы работы механизмов сериализации, десериализации и схемы перед тем, как уклониться от выполнения правил.

См. также

Справочник

Name
DataContractAttribute
Order
IsRequired
IExtensibleDataObject
ServiceBehaviorAttribute
ExtensionData
ExtensionDataObject
OnDeserializingAttribute

Основные понятия

Использование контрактов данных
Управление версиями контракта данных
Имена контрактов данных
Контракты данных, совместимые с любыми будущими изменениями
Обратные вызовы сериализации, независимые от версий