Сделать клиент веб-сервиса совместимым с новыми серверами

У нас есть клиент.NET, который использует прокси-класс (производный от System.Web.Services.Protocols.SoapHttpClientProtocol) генерируется из файла wsdl с помощью wsdl.exe.

До сих пор у нас была хорошая совместимость между клиентом и веб-сервисом для большинства изменений веб-сервиса. Старый клиент (со старым прокси, сгенерированным из старого файла wsdl) просто не будет вызывать новые методы веб-сервиса.
Единственная проблема - это расширение типа enum (xsd.enumeration). Это специальное перечисление используется во многих get... звонки.

пример

WSDL

  <xsd:simpleType name="Colors">
    <xsd:restriction base="xsd:string">
      <xsd:enumeration value="Red"/>
      <xsd:enumeration value="Blue"/>
      <xsd:enumeration value="Unspecified"/>
    </xsd:restriction>
  </xsd:simpleType>

Код прокси, сгенерированный из WSDL

[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:archive.admin.services.ecm.opentext.com")]
public enum Colors { Red, Blue, Unspecified }

ошибка

Клиент знает перечисление Colors со значениями Red, Blue а также Unspecified, Если сервер возвращает новое значение перечисления, например Yellow мы получаем ошибку:

Instance validation error: 'Yellow' is not a valid value for Colors.
Exception Class: System.InvalidOperationException
StackTrace:
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderArchiveAdministrationService.Read2_Keys(String s)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderArchiveAdministrationService.Read6_ResultField(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderArchiveAdministrationService.Read7_ResultRecord(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderArchiveAdministrationService.Read10_invokeCommandResponse()
   at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer.Deserialize(XmlSerializationReader reader)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
There is an error in XML document (1, 1557).
Exception Class: System.InvalidOperationException
StackTrace:
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)

Эта ошибка верна, потому что это перечисление. Но я искал прагматичный способ избежать этого исключения. Вы видите в stacktrace, что исключение выдается кодом, который десериализует данные XML ответа в перечисление C# прокси. Наш собственный код уже может игнорировать неизвестное значение перечисления, например Yellow, Но десериализация.NET не знает наших потребностей.

Я уже нашла SoapExtensions, Но тогда мне нужно будет проанализировать весь XML-контент каждого ответа веб-сервиса.

У вас есть идея / решение / обходной путь, чтобы избежать выше исключения? Пожалуйста, не предупреждайте меня, что "это плохо", "wsdl - это контракт" и так далее. Я хочу просто прагматичное решение.:-)

1 ответ

Решение

Я сделал это с помощью SoapExtension. Я взял образец TraceExtension и изменил его так, что каждый XML-ответ проверяется на наличие неизвестных enum литералы. Если он найден, расширение заменяет его в XML неиспользованным enum буквальный (Unspecified).
Код клиента игнорирует литерал Unspecified затем.

Но осталась одна проблема: веб-метод должен получить SoapExtensionAttribute (подкласс). Но прокси-класс с этим веб-методом является сгенерированным кодом (из *.wsdl). Поэтому мы должны устанавливать этот атрибут каждый раз, когда генерируется код. Другой вариант по конфигурации imo невозможен, потому что у нас есть MMC Snap-In, *.dll.

Другие вопросы по тегам