Подтвердить что ты не робот

Проблемы сериализации WCF с файлом WSDL, созданным инструментами Java

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

Тем не менее, мы пытаемся использовать 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

Когда я просматриваю файл класса autogenerated proxy class.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, который они создают, является документом-документом. После некоторых исследований в Интернете, по-видимому, WCF по умолчанию. переводит WSDL файлы с завершенным документом-документом, и это может объяснить, по крайней мере, частично, почему мы видим эту проблему сериализации WCF с файлом WSDL.

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

[System.Xml.Serialization.XmlAttributeAttribute()]

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Пример:

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

Ответ 2

На основе сгенерированного кода похоже, что ваш 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;  
}     

Ответ 3

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

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

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

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

Ответ 4

В качестве последующего ответа на stratovarius в VS 2017 папка "Ссылки на службы" заменяется подключенными службами, поэтому вам необходимо:

  • Откройте папку {project}/Connected Services в проводнике Windows
  • Найти и отредактировать Reference.svcmap с помощью текстового редактора
  • Добавить <Wrapped>true</Wrapped> в раздел <ClientOptions>
  • Сохранить файл
  • В VS щелкните правой кнопкой мыши ссылку на службу в разделе Подключенные службы и выберите "Обновить ссылку на службу"

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