Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
После первоначального развертывания и потенциально несколько раз во время их существования службы (и конечные точки, которые они предоставляют) могут быть изменены по различным причинам, таким как изменение бизнес-потребностей, требований к информационным технологиям или решение других проблем. Каждое изменение представляет новую версию службы. В этом разделе объясняется, как рассмотреть возможность управления версиями в Windows Communication Foundation (WCF).
Четыре категории изменений службы
Изменения служб, которые могут потребоваться, можно классифицировать по четырем категориям:
Изменения контракта: например, может быть добавлена операция или элемент данных в сообщении может быть добавлен или изменен.
Изменения адресов: например, служба перемещается в другое расположение, где конечные точки имеют новые адреса.
Изменения настроек: например, механизм безопасности меняется или меняются его настройки.
Изменения реализации: например, при изменении реализации внутреннего метода.
Некоторые из этих изменений называются "критическими" и другими являются "неразрывными". Изменение неразрывно , если все сообщения, которые были успешно обработаны в предыдущей версии, успешно обрабатываются в новой версии. Любое изменение, которое не соответствует такому критерию, является критическим изменением.
Ориентация службы и управление версиями
Одним из принципов ориентации службы является то, что службы и клиенты являются автономными (или независимыми). Помимо прочего, это означает, что разработчики служб не могут предположить, что они контролируют или даже знают обо всех клиентах служб. Это устраняет возможность перестроения и повторного развертывания всех клиентов при изменении версий службы. В этом разделе предполагается, что служба соответствует данному основному принципу и поэтому должна быть изменена или "версирована" независимо от своих клиентов.
В случаях, когда критическое изменение непредвиденное и не удается избежать, приложение может игнорировать этот принцип и требовать, чтобы клиенты были перестроены и повторно развернуты с новой версией службы.
Управление версиями контракта
Контракты, используемые клиентом, не должны совпадать с контрактом, используемым службой; они должны быть совместимы только.
Для сервисных контрактов совместимость означает, что новые операции, предоставляемые службой, можно добавить, но существующие операции нельзя удалить или изменить их семантику.
Для контрактов данных совместимость означает, что новые определения типов схемы могут быть добавлены, но существующие определения типов схемы не могут быть изменены способами, нарушающими работу. Критические изменения могут включать удаление членов данных или несовместимое изменение их типа данных. Эта функция предоставляет службе некоторую свободу изменять версию своих контрактов, не нарушая работу клиентов. В следующих двух разделах описываются неразрывные и критические изменения, которые можно вносить в данные WCF и контракты служб.
Управление версиями контракта данных
В этом разделе рассматривается версионирование данных при использовании классов DataContractSerializer и DataContractAttribute.
Строгое управление версиями
Во многих сценариях при изменении версий возникает проблема, разработчик службы не имеет контроля над клиентами и поэтому не может делать предположений о том, как они будут реагировать на изменения в XML-коде сообщения или схеме. В таких случаях необходимо гарантировать, что новые сообщения будут проверяться по старой схеме по двум причинам:
Старые клиенты были разработаны с предположением, что схема останется неизменной. Они могут не обрабатывать сообщения, для которых они не предназначены.
Старые клиенты могут выполнять действительную проверку соответствия по старой схеме еще до попытки обработать сообщения.
Рекомендуемый подход в таких сценариях — рассматривать существующие контракты данных как неизменяемые и создавать новые с уникальными именами XML. Затем разработчик службы добавит новые методы в существующий контракт службы или создадит новый контракт службы с методами, используюющими новый контракт данных.
Зачастую разработчик службы должен писать некоторую бизнес-логику, которая должна выполняться во всех версиях контракта данных и бизнес-коде конкретной версии для каждой версии контракта данных. В приложении в конце этого раздела объясняется, как интерфейсы можно использовать для удовлетворения этой потребности.
Легкая версионность
Во многих других сценариях разработчик службы может сделать предположение о том, что добавление нового необязательного члена в контракт данных не приведет к разрыву существующих клиентов. Это требует, чтобы разработчик службы проверял, не выполняют ли существующие клиенты проверку схемы и игнорируют неизвестные члены данных. В этих сценариях можно воспользоваться функциями контракта данных для добавления новых членов ненарушающим способом. Разработчик службы может сделать это предположение с уверенностью, если функции контракта данных для управления версиями уже использовались для первой версии службы.
WCF, ASP.NET Web Services и многие другие стеки веб-служб поддерживают гибкое управление версиями: то есть они не вызывают исключений для новых неизвестных элементов данных в полученных данных.
Легко ошибочно поверить, что добавление нового члена не приведет к разрыву существующих клиентов. Если вы не уверены, что все клиенты могут обрабатывать упрощенное управление версиями, советуем использовать строгие рекомендации по управлению версиями и считать контракты данных неизменяемыми.
Подробные рекомендации по гибкому и строгому управлению версиями контрактов данных см. в Лучшие практики: управление версиями контрактов данных.
Различие между контрактами данных и типами .NET
Класс или структура .NET можно проецировать в виде контракта данных, применяя DataContractAttribute атрибут к классу. Тип .NET и его проекции контракта данных являются двумя различными вопросами. Существует несколько типов .NET с одной проекцией контракта данных. Это различие особенно полезно для изменения типа .NET при сохранении прогнозируемого контракта данных, тем самым обеспечивая совместимость с существующими клиентами даже в строгом смысле слова. Чтобы сохранить это различие между типом .NET и контрактом данных, всегда следует выполнять две следующие задачи.
Укажите Name и Namespace. Всегда следует указать имя и пространство имен вашего контракта данных, чтобы предотвратить случайное предоставление имени и пространства имен вашего типа .NET в контракте. Таким образом, если вы решите изменить пространство имен .NET или имя типа, контракт данных остается неизменным.
Укажите Name. Всегда следует указывать название участников данных, чтобы предотвратить раскрытие имени члена .NET в контракте. Таким образом, если вы решите изменить имя члена .NET, контракт данных остается неизменным.
Изменение или удаление участников
Изменение имени или типа данных члена или удаление элементов данных является критическим изменением даже в том случае, если разрешено неустранимое управление версиями. При необходимости создайте новый контракт данных.
Если совместимость служб имеет высокую важность, вы можете игнорировать неиспользуемые элементы данных в коде и оставить их на месте. Если вы разделяете элемент данных на несколько членов, вы можете оставить существующий элемент на месте в качестве свойства, которое может выполнять необходимое разделение и повторное агрегирование для клиентов нижнего уровня (клиенты, которые не обновлены до последней версии).
Аналогичным образом, изменения в имени или пространстве имен контракта данных являются разрушающими изменениями.
Round-Trips неизвестных данных
В некоторых сценариях требуется "перенос" неизвестных данных, поступающих из элементов, добавленных в новую версию. Например, служба versionNew отправляет данные с некоторыми новыми добавленными участниками в клиент versionOld. Клиент игнорирует только что добавленные члены при обработке сообщения, но он повторно отправляет те же данные, в том числе только что добавленные члены, обратно в службу versionNew. Типичным сценарием этого является обновление данных, в котором данные извлекаются из службы, изменяются и возвращаются.
Чтобы включить циклический обход для определенного типа, тип должен реализовать IExtensibleDataObject интерфейс. Интерфейс содержит одно свойство, ExtensionData которое возвращает ExtensionDataObject тип. Свойство используется для хранения любых данных из будущих версий контракта данных, которые неизвестны текущей версии. Эти данные непрозрачны для клиента, но при сериализации экземпляра содержимое ExtensionData свойства записывается с остальными данными членов контракта данных.
Рекомендуется, чтобы все ваши типы реализовали этот интерфейс для размещения новых и неизвестных будущих членов.
Библиотеки контрактов данных
Могут быть библиотеки контрактов данных, в которых контракт публикуется в центральном репозитории, а разработчики служб и типов реализуют и предоставляют контракты данных из этого репозитория. В этом случае при публикации контракта данных в репозитории нет контроля над тем, кто создает типы, реализующие его. Таким образом, вы не можете изменить контракт после публикации, делая его по сути неизменяемым.
При использовании XmlSerializer
Те же принципы управления версиями применяются при использовании XmlSerializer класса. Если требуется строгое управление версиями, обработайте контракты данных как неизменяемые и создайте новые контракты данных с уникальными, квалифицированными именами для новых версий. Если вы уверены, что гибкое управление версиями можно использовать, можно добавлять новые сериализуемые элементы в новых версиях, но не изменять или удалять существующие элементы.
Замечание
Элемент XmlSerializer использует атрибуты XmlAnyElementAttribute и XmlAnyAttributeAttribute для поддержки возвратного преобразования неизвестных данных.
Управление версиями контракта сообщений
Рекомендации по версионированию контрактов сообщений очень похожи на версионирование контрактов данных. Если требуется строгое управление версиями, не следует изменять текст сообщения, а вместо этого следует создать новый контракт сообщения с уникальным квалифицированным именем. Если вы знаете, что вы можете использовать нестрогое управление версиями, можно добавить новые части текста сообщения, но не изменять или удалять существующие. Это руководство применяется как к контрактам сообщений без оболочки, так и к контрактам с оболочкой.
Заголовки сообщений всегда можно добавлять, даже если используется строгое управление версиями. Флаг MustUnderstand может повлиять на управление версиями. Как правило, модель управления версиями для заголовков в WCF описана в спецификации SOAP.
Управление версиями контракта службы
Как и управление версиями контракта данных, управление версиями контракта службы также включает добавление, изменение и удаление операций.
Указание имени, пространства имен и действия
По умолчанию имя контракта службы — это имя интерфейса. Его пространство имен по умолчанию — http://tempuri.org, а действие каждой операции — http://tempuri.org/contractname/methodname. Рекомендуется явно указать имя и пространство имен для контракта службы, а также действие для каждой операции, чтобы избежать использования http://tempuri.org и предотвратить раскрытие имен интерфейсов и методов в контракте службы.
Добавление параметров и операций
Добавление операций служб, предоставляемых службой, является неразрывным изменением, так как существующие клиенты не должны беспокоиться об этих новых операциях.
Замечание
Добавление операций в дуплексный контракт обратного вызова является критическим изменением.
Изменение параметров операции или типов возвращаемых значений
Изменение параметров или возвращаемых типов обычно является критическим изменением, если только новый тип не реализует тот же контракт данных, реализованный старым типом. Чтобы внести такое изменение, добавьте новую операцию в контракт службы или определите новый контракт службы.
Удаление операций
Удаление операций также является критическим изменением. Чтобы внести такое изменение, определите новый контракт службы и предоставьте его на новой точке доступа.
Контракты сбоя
Атрибут FaultContractAttribute позволяет разработчику сервисного контракта указывать сведения об ошибках, которые могут быть возвращены из операций контракта.
Список сбоев, описанных в контракте службы, не считается исчерпывающим. В любой момент операция может возвращать неполадки, которые не описаны в контракте. Поэтому изменение набора ошибок, описанных в контракте, не считается нарушением. Например, добавление нового сбоя в контракт с помощью FaultContractAttribute или удаления существующего сбоя из контракта.
Библиотеки контрактов службы
Организации могут иметь библиотеки контрактов, в которых контракт публикуется в центральном репозитории, и сервисные реализаторы реализуют контракты из этого репозитория. В этом случае при публикации контракта службы в репозитории у вас нет контроля над тем, кто создает службы, реализующие его. Поэтому нельзя изменить контракт службы после его публикации, что делает его по сути неизменяемым. WCF поддерживает наследование контракта, которое можно использовать для создания нового контракта, который расширяет существующие контракты. Чтобы использовать эту функцию, определите новый интерфейс контракта службы, наследуемый от старого интерфейса контракта службы, а затем добавьте методы в новый интерфейс. Затем вы измените службу, которая реализует старый контракт для реализации нового контракта и измените определение конечной точки versionOld, чтобы использовать новый контракт. Для клиентов versionOld конечная точка будет продолжать отображаться как предоставляющая контракт versionOld; для клиентов versionNew она будет отображаться как предоставляющая контракт versionNew.
Версионирование адресов и привязок
Изменения адреса конечной точки и привязки являются критическими изменениями, если клиенты не могут динамически обнаруживать новый адрес конечной точки или привязку. Одним из механизмов реализации этой возможности является использование реестра универсального обнаружения и интеграции (UDDI) и шаблона вызова UDDI, в котором клиент пытается взаимодействовать с конечной точкой и после сбоя запрашивает известный реестр UDDI для текущих метаданных конечной точки. Затем клиент использует адрес и привязку из этих метаданных для взаимодействия с конечной точкой. Если это взаимодействие выполнено успешно, клиент кэширует сведения об адресе и привязке для дальнейшего использования.
Служба маршрутизации и управление версиями
Если внесенные в службу изменения являются критическими и вам нужно одновременно работать с двумя или более версиями службы, вы можете использовать маршрутизатор WCF для направления сообщений к соответствующему экземпляру службы. Служба маршрутизации WCF использует маршрутизацию на основе содержимого, другими словами, она использует сведения в сообщении, чтобы определить, куда направлять сообщение. Дополнительные сведения о службе маршрутизации WCF см. в разделе "Служба маршрутизации". Пример использования службы маршрутизации WCF для управления версиями служб см. в статье "Практическое руководство. Управление версиями служб".
Приложение
Общее руководство по использованию версий контракта данных, когда требуется строгое управление версиями, заключается в том, чтобы рассматривать контракты данных как неизменяемые и создавать новые при необходимости изменений. Для каждого нового контракта данных необходимо создать новый класс, поэтому необходимо избежать необходимости принимать существующий код, написанный с точки зрения старого класса контракта данных, и переписать его с точки зрения нового класса контракта данных.
Один из таких механизмов — использовать интерфейсы для определения членов каждого контракта данных и написания внутреннего кода реализации с точки зрения интерфейсов, а не классов контрактов данных, реализующих интерфейсы. В следующем коде для версии 1 службы показаны интерфейс IPurchaseOrderV1 и PurchaseOrderV1:
public interface IPurchaseOrderV1
{
string OrderId { get; set; }
string CustomerId { get; set; }
}
[DataContract(
Name = "PurchaseOrder",
Namespace = "http://examples.microsoft.com/WCF/2005/10/PurchaseOrder")]
public class PurchaseOrderV1 : IPurchaseOrderV1
{
[DataMember(...)]
public string OrderId {...}
[DataMember(...)]
public string CustomerId {...}
}
Хотя операции договора о предоставлении услуг будут оформлены в терминах PurchaseOrderV1, фактическая бизнес-логика будет представлена в терминах IPurchaseOrderV1. Затем в версии 2 будет новый интерфейс и новый IPurchaseOrderV2PurchaseOrderV2 класс, как показано в следующем коде:
public interface IPurchaseOrderV2
{
DateTime OrderDate { get; set; }
}
[DataContract(
Name = "PurchaseOrder",
Namespace = "http://examples.microsoft.com/WCF/2006/02/PurchaseOrder")]
public class PurchaseOrderV2 : IPurchaseOrderV1, IPurchaseOrderV2
{
[DataMember(...)]
public string OrderId {...}
[DataMember(...)]
public string CustomerId {...}
[DataMember(...)]
public DateTime OrderDate { ... }
}
Контракт службы будет обновлен, чтобы включить в себя новые операции, описанные в терминах PurchaseOrderV2. Существующая бизнес-логика, определенная в терминах IPurchaseOrderV1, будет продолжать работать для PurchaseOrderV2, а новая бизнес-логика, которая требует свойства OrderDate, будет написана с использованием IPurchaseOrderV2.