2010-10-01 3 views
12

Моя команда имеет задачу получить несколько встроенных клиентских приложений .NET для подключения к некоторым новым веб-службам Java. Веб-сервис Java является сторонним поставщиком, поставляемым поставщиком WSDL-файла, который имеет ограниченную способность изменять/контролировать нашу команду ... что мы, вероятно, имеем право просить нашего поставщика сделать небольшие изменения в WSDL, но серьезные изменения, вероятно, быть либо неосуществимым, либо трудно запросить.Проблемы с сериализацией WCF с файлом WSDL, созданным инструментами Java

Это говорит о том, что мы пытаемся использовать WCF/.NET 4.0 для создания файлов классов прокси .NET, которые нам нужны на стороне клиента. Процесс генерации файлов класса прокси-сервера выполняется без проблем.

Проблема заключается в том, что мы пытаемся использовать файл класса прокси в клиентском приложении. Я проверил через инструмент веб-трассировки Fiddler, что необработанный запрос SOAP-сообщения не может быть отправлен по проводке на сервер.

Конкретное сообщение .NET исключение я получаю при попытке вызова метода веб-службы в вопросе, выглядит следующим образом:

System.InvalidOperationException было необработанное Message = атрибут XmlSerializer System.Xml.Serialization.XmlAttributeAttribute является недействителен в baseLanguage. Только атрибуты XmlElement, XmlArray, XmlArrayItem, XmlAnyAttribute и XmlAnyElement поддерживаются, когда IsWrapped истинно. Источник = System.ServiceModel

Когда я анализирую файл класса .NET автоматически генерируемый прокси, Reference.cs, я заметил, что сообщения запросов и ответов для моего метода веб-службы выглядит примерно так:

[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] 
[System.ServiceModel.MessageContractAttribute(WrapperName="QueryPBOT_MXWO_OS", WrapperNamespace="http://www.ibm.com/maximo", IsWrapped=true)] 
public partial class QueryPBOT_MXWO_OSRequest { 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=0)] 
    public ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=1)] 
    [System.Xml.Serialization.XmlAttributeAttribute()] 
    public string baseLanguage; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=2)] 
    [System.Xml.Serialization.XmlAttributeAttribute()] 
    public string transLanguage; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=3)] 
    [System.Xml.Serialization.XmlAttributeAttribute()] 
    public string messageID; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=4)] 
    [System.Xml.Serialization.XmlAttributeAttribute()] 
    public string maximoVersion; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=5)] 
    [System.Xml.Serialization.XmlAttributeAttribute()] 
    [System.ComponentModel.DefaultValueAttribute(false)] 
    public bool uniqueResult; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=6)] 
    [System.Xml.Serialization.XmlAttributeAttribute(DataType="positiveInteger")] 
    public string maxItems; 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=7)] 
    [System.Xml.Serialization.XmlAttributeAttribute(DataType="integer")] 
    [System.ComponentModel.DefaultValueAttribute("0")] 
    public string rsStart; 

    public QueryPBOT_MXWO_OSRequest() { 
    } 

    public QueryPBOT_MXWO_OSRequest(ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery, string baseLanguage, string transLanguage, string messageID, string maximoVersion, bool uniqueResult, string maxItems, string rsStart) { 
     this.PBOT_MXWO_OSQuery = PBOT_MXWO_OSQuery; 
     this.baseLanguage = baseLanguage; 
     this.transLanguage = transLanguage; 
     this.messageID = messageID; 
     this.maximoVersion = maximoVersion; 
     this.uniqueResult = uniqueResult; 
     this.maxItems = maxItems; 
     this.rsStart = rsStart; 
    } 
} 

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

Я надеюсь, что автогенерированный прокси-файл клиента и исключение .NET помогут кому-то распознать эту проблему сериализации WCF.

Мы подтвердили от нашего поставщика Java, что стиль WSDL, который они создают, является doc-literal. После некоторых исследований в Интернете, по-видимому, WCF по умолчанию. переводит файлы WSDL с завершенным документом-документом, и это может объяснить, по крайней мере, частично, почему мы видим эту проблему сериализации WCF с WSDL-файлом.

Я обнаружил, путем проб и ошибок, что следующий атрибут декоратор в файле прокси-класса является виновником вопроса сериализации:

[System.Xml.Serialization.XmlAttributeAttribute()]

Если я прокомментирую все экземпляры этого атрибута в файле прокси-класса и повторно запустил приложение-клиент, сообщение SOAP успешно отправляется по сети, и я получаю действительный ответ веб-службы, возвращаемый с сервера.

Это исправление лучше, чем ничего, но я бы очень предпочел решение, которое не требует, чтобы я или кто-либо из моей команды постоянно настраивал эти файлы с автогенерированным прокси-сервером .NET.

Я хотел бы знать, есть ли что-то, что я могу сделать, либо с помощью различных инструментов WCF, либо путем изменения файла WSDL, что предотвращает применение метода [System.Xml.Serialization.XmlAttributeAttribute()] к моему запросу и свойства объекта ответа?

Или, по крайней мере, описание высокого уровня ПОЧЕМУ мы видим это поведение сериализации в .NET с Java WSDL-файлом?

заранее спасибо, Джон

+0

Является ли XmlAttributeAttribute добавленным вами или сгенерированным WCF? –

+0

XMLAttributeAttribute генерируется инструментами WCF, и я не понимаю, почему. Если в инструменте есть какой-то переключатель, чтобы предотвратить его создание или что-то, что мы можем изменить в исходном WSDL-файле, мы можем избежать настройки файла класса прокси, чтобы он работал. –

+0

У вас есть образец рабочего запроса на мыло от вашего поставщика Java? –

ответ

3

на основе сгенерированного кода это выглядит как ваш сервис Java ожидает запрос как:

<s:Envelope xmlns:s="..."> 
    ... 
    <s:Body> 
    <QueryPBOT_MXWO_OS xmlns="http://www.ibm.com/maximo" baseLanguage="..." transLanguage="..." ...> 
     <PBOT_MXWO_OSQuery> 
     ... 
     </PBOT_MXWO_OSQuery> 
    </QueryPBOT_MXWO_OS> 
    </s:Body> 
</s:Envelope> 

Проблема заключается в том, что WCF признана QueryPBOT_MXWO_OS в качестве оберточного элемента для запроса. Я не уверен, почему он запускает исключение, но, вероятно, есть некоторые ограничения, что элемент-оболочка не может иметь атрибуты. Я подозрительно, что это всего лишь глобальная обработка ошибок, совместно используемая версией, которая использует IsWrapped = false, где использование атрибутов является ошибкой.

Вы можете попытаться изменить ваш прокси-сервер таким образом:

[System.Diagnostics.DebuggerStepThroughAttribute()]   
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]   
[System.ServiceModel.MessageContractAttribute(IsWrapped=false)]   
public partial class QueryPBOT_MXWO_OSRequest 
{ 
    [MessageBodyMemberAttribute(Name="QueryPBOT_MXWO_OS", Namespace="http://www.ibm.com/maximo")] 
    public QueryPBOT_MXWO_OS QueryPBOT_MXWO_OS { get; set; } 
} 

[XmlRoot(ElementName="QueryPBOT_MXWO_OS", Namespace="http://www.ibm.com/maximo")] 
public class QueryPBOT_MXWO_OS 
{ 
    [XmlElement(Namespace="http://www.ibm.com/maximo")]  
    public ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]   
    public string baseLanguage;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]   
    public string transLanguage;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]  
    public string messageID;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]  
    public string maximoVersion;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]  
    [System.ComponentModel.DefaultValueAttribute(false)]   
    public bool uniqueResult;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]  
    public string maxItems;   

    [XmlAttribute(Namespace="http://www.ibm.com/maximo")]   
    [System.ComponentModel.DefaultValueAttribute("0")]   
    public string rsStart; 
}  
+0

Laislav, спасибо за ваш комментарий, но то, что я действительно ищу, - это решение, в котором мне не нужно прикоснуться к файлу класса прокси вообще, чтобы заставить работать веб-сервис. Если я прокомментирую все экземпляры [XmlAttribute()] из файла прокси-класса, веб-служба будет работать. –

+1

Но в этом случае все эти параметры переносятся как элементы. Вам нужны эти параметры? Если не просто удалить их из WSDL и восстановить прокси. –

9

Использование svcutil.exe утилита с /обернутой опции для генерации прокси-классов.

Это создаст несколько разные классы, чем те, которые были созданы в Visual Studio таким образом, как это описано Ladislav Mrnka. При использовании на стороне клиента результирующие прокси должны быть свободны от проблемы XmlAttribute.

Пример:

svcutil /t:code wsdl.xml /out:wsdl.cs /serializer:XmlSerializer /wrapped 
2

Вот как сделать решение Михаила G в пределах IDE:

  • Открыть Reference.svcmap под службы Ссылки
  • Добавить <Wrapped>true</Wrapped> под <ClientOptions> и Сохранить
  • Right Нажмите «Ссылка.svcmap» и нажмите «Запустить пользовательский инструмент»

Visual Studio, где происходит волшебство :)

Примечание: Пробовал с VS 2015. Предыдущие версии могут иметь такой же вариант с другим именем, чем "запустить пользовательский инструмент"

+1

Удивительно, это решило мою проблему! –

1

Как последующий на ответ Stratovarius, в в VS 2017 папка Сервис Рекомендации заменяется Connected Services, так что вы должны:

  1. Откройте {}/проекта Connected папку Услуги в Wi ndows Проводник
  2. Найти и редактировать Reference.svcmap с помощью текстового редактора
  3. Добавить <Wrapped>true</Wrapped> в <ClientOptions> секции
  4. Сохранить файл
  5. В VS, щелкните правой кнопкой мыши по ссылке сервиса под Connected Services и выберите «Обновить Service Reference "

Это освободило исключение из моего служебного вызова.

Смежные вопросы