Сделать клиент веб-сервиса совместимым с новыми серверами
У нас есть клиент.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.