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


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

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

Критические и некритические изменения

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

Любые изменения типа, не влияющие на способ его передачи и приема, являются некритическими. Такие изменения не изменяют контракт данных, они изменяют только базовый тип. Например, изменение имени поля будет некритическим, если затем задать для свойства Name атрибута DataMemberAttribute имя из старой версии. В следующем коде показана версия 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;
}

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

  • Изменение значения Name или Namespace контракта данных.

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

  • Переименование члена данных.

  • Изменение контракта данных члена данных. Например, изменение типа члена данных с целого числа на строку или с типа, имеющего контракт данных с именем "Заказчик" на тип, имеющий контракт данных с именем "Личность".

Возможны также указанные ниже изменения.

Добавление и удаление членов данных

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

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

Когда тип с отсутствующим полем десериализуется в тип с дополнительным полем, для дополнительного поля сохраняется значение по умолчанию, обычно ноль или 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>

Механизм десериализации в V1 не находит соответствующего члена данных для поля HorsePower и отбрасывает эти данные.

Конечная точка версии 1 также может передать данные конечной точке версии 2. В результате сериализации версии 1 контракта данных Car получается код XML, аналогичный приведенному ниже.

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

Десериализатор версии 2 не знает, какое значение следует присвоить полю HorsePower, поскольку во входящем коде XML нет соответствующих данных. В результате этому полю присваивается значение по умолчанию "0".

Обязательные члены данных

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

Добавление обязательного члена данных — это критическое изменение. То есть, новый тип можно передавать на конечные точки старого типа, но не наоборот. Удаление члена данных, помеченного в старой версии как обязательный, также является критическим изменением.

Изменение значения свойства IsRequired с true на false не является критическим изменением, а изменение со значения false на значение true может быть критическим, если в какой-либо предыдущей версии этого типа соответствующий член данных отсутствует.

ms731138.note(ru-ru,VS.100).gifПримечание
Даже если для свойства IsRequired задано значение true, входящие данные могут иметь значение "null" или ноль, и тип должен быть готов к обработке такой ситуации. Не используйте значение IsRequired в качестве механизма защиты от неправильных входных данных.

Опущенные значения по умолчанию

Можно (хотя и не рекомендуется) задать для свойства EmitDefaultValue атрибута DataMemberAttribute значение false, как описано в разделе Значения элементов данных по умолчанию. Если задано значение false, член данных не передается, если для него установлено значение по умолчанию (обычно "null" или ноль). Это не совместимо с обязательными членами данных в различных версиях по двум причинам.

  • Контракт данных, содержащий член данных, обязательный в одной версии, не может принимать данные по умолчанию ("null" или ноль) из другой версии, в которой для свойства EmitDefaultValue этого члена данных задано значение false.

  • Обязательный член данных, для свойства EmitDefaultValue которого задано значение false, не может использоваться для сериализации его значения по умолчанию ("null" или ноль), но может получить такое значение при десериализации. Это создает проблему при круговой передаче (данные можно считать, но эти же данные невозможно потом записать). Поэтому если в одной версии для свойства IsRequired задано значение true и для свойства EmitDefaultValue задано значение false, это же сочетание должно применяться во всех остальных версиях, чтобы ни одна из версий контракта данных не могла создать значение, которое не сможет пройти круговую передачу.

Замечания по схемам

Описание схемы, создаваемой для типов контрактов данных, см. в разделе Справочник по схеме контрактов данных.

Схема, которую WCF создает для типов контракта данных, не поддерживает управление версиями. Это означает, что схема, экспортированная из определенной версии типа, содержит только те члены данных, которые присутствуют в этой версии. Реализация интерфейса IExtensibleDataObject не изменяет схему для типа.

По умолчанию члены данных экспортируются в схему как необязательные элементы. То есть значение minOccurs (XML-атрибут) равно 0. Необходимые члены данных экспортируются, если параметр minOccurs имеет значение 1.

Многие изменения, считающиеся некритическими, на самом деле являются критическими, если требуется строгое соответствие схеме. В предыдущем примере экземпляр CarV1, содержащий только элемент Model, пройдет проверку по схеме CarV2 (содержащую элементы Model и Horsepower, оба необязательные). Однако обратное неверно: экземпляр CarV2 не пройдет проверку по схеме CarV1.

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

Другие разрешенные изменения

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

Перечисления

Добавление или удаление члена перечисления — это критическое изменение. Изменение имени члена перечисления также является критическим изменением, за исключением случая, когда с помощью атрибута EnumMemberAtttribute имя контракта оставлено таким же, как и в старой версии. Дополнительные сведения см. в разделе Типы перечислений в контрактах данных.

Коллекции

Большинство изменений коллекций являются некритическими, так как в модели контракта данных большинство типов коллекции взаимозаменяемы. Однако преобразование стандартной коллекции в настраиваемую или наоборот является критическим изменением. Кроме того, изменение параметров настройки коллекции — это критическое изменение; т. е., изменение ее имени контракта данных и пространства имен, имени повторяющегося элемента, имени ключевого элемента и имени элемента значения. Дополнительные сведения настройке коллекции см. в разделе Типы коллекций в контрактах данных.

Естественно, что изменение контракта данных содержимого коллекции (например, изменение списка целых чисел на список строк) является критическим изменением.

См. также

Справочник

Name
DataMemberAttribute
Name
Namespace
Order
IsRequired
SerializationException
IExtensibleDataObject

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

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