Проблемы сериализации WCF с файлом WSDL, созданным инструментами Java - PullRequest
12 голосов
/ 01 октября 2010

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

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

[System.Xml.Serialization.XmlAttributeAttribute ()]

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

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

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

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

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

Ответы [ 4 ]

11 голосов
/ 07 сентября 2012

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

Это создаст несколько другие классы, чем классы, созданные в Visual Studio способом, описанным здесь Ладиславом Мрнкой. Результирующие прокси должны быть свободны от проблемы XmlAttribute при использовании на стороне клиента.

Пример:

svcutil /t:code wsdl.xml /out:wsdl.cs /serializer:XmlSerializer /wrapped
4 голосов
/ 09 февраля 2017

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

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

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

Примечание.иметь ту же опцию с именем, отличным от «Запустить пользовательский инструмент»

3 голосов
/ 02 октября 2010

Исходя из сгенерированного кода, похоже, что ваш 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;  
}     
2 голосов
/ 09 августа 2017

Как ответ на стратовариус, в VS 2017 папка Service References заменена на Connected Services, поэтому вам необходимо:

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

Это исключило исключение из моего сервисного звонка.

...