Клиент WCF / веб-служба Java - десериализованные объекты являются нулевыми - PullRequest
4 голосов
/ 13 октября 2011

Я пытаюсь интегрировать веб-сервис Java в мой проект C #.Веб-служба обслуживается другим подразделением моей компании и находится вне моего контроля.

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

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

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

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace = "www.namespace1.com", ConfigurationName = "MyService.MyServiceClient")]
public interface MyServiceClient
{
    [System.ServiceModel.OperationContractAttribute(Action = "", ReplyAction = "*")]
    [System.ServiceModel.XmlSerializerFormatAttribute(Style = System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults = true, Use = System.ServiceModel.OperationFormatUse.Encoded)]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyOperationResponseType))]
    myOperationResponse myOperation(myOperationRequest request);    
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.SoapTypeAttribute(Namespace = "www.namespace2.com")]
public partial class MyOperationResponseType : object, System.ComponentModel.INotifyPropertyChanged
{
    private bool callSuccessfulField;

    private string callErrorMessageField;

    /// <remarks/>
    public bool CallSuccessful
    {
        get
        {
            return this.callSuccessfulField;
        }
        set
        {
            this.callSuccessfulField = value;
            this.RaisePropertyChanged("CallSuccessful");
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.SoapElementAttribute(IsNullable = true)]
    public string CallErrorMessage
    {
        get
        {
            return this.callErrorMessageField;
        }
        set
        {
            this.callErrorMessageField = value;
            this.RaisePropertyChanged("CallErrorMessage");
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if ((propertyChanged != null))
        {
            propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName = "myOperationResponse", WrapperNamespace="www.namespace1.com", IsWrapped = true)]
public partial class myOperationResponse
{

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace = "", Order = 0)]
    public MyOperationResponseType result;

    public myOperationResponse()
    {
    }

    public myOperationResponse(MyOperationResponseType result)
    {
        this.result = result;
    }
}

Ответ SOAP, который я получаю, выглядит следующим образом:

<env:Envelope env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<m:myOperationResponse xmlns:m="www.namespace1.com">
<result>
<ns2:CallSuccessful xmlns:ns2="www.namespace2.com">false</ns2:CallSuccessful>
<ns2:CallErrorMessage xmlns:ns2="www.namespace2.com">Failed for some reason.</ns2:CallErrorMessage>
</result>
</m:myOperationResponse>
</env:Body>
</env:Envelope>

Экземпляр MyOperationResponseType создается, но CallErrorMessage и CallSuccessfulполя не заполнены.

Я использовал SGEN для генерации классов сериализации XML и обнаружил, что это проблема пространства имен.Следующие отрывки кода взяты из десериализатора:

string id2_Item;
id2_Item = Reader.NameTable.Add(@"");

global::MyOperationResponseType o;
o = new global::MyOperationResponseType();

if (!paramsRead[1] && ((object) Reader.LocalName == (object)id158_CallSuccessful && (object) Reader.NamespaceURI == (object)id2_Item)) {
    {
        o.@CallSuccessful = System.Xml.XmlConvert.ToBoolean(Reader.ReadElementString());
    }
paramsRead[1] = true;
}

Условное условие не выполняется, поскольку Reader.NamespaceURI = "www.namespace2.com" и id2_Item = ""

Если я вручную установлю id2_Item = "www.namespace2.com", то десериализация будет работать.

Кроме того, если я удаляю пространства имен из ответа SOAP, он будет работать:

<env:Envelope env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<m:myOperationResponse xmlns:m="www.namespace1.com">
<result>
<CallSuccessful>false</CallSuccessful>
<CallErrorMessage>Failed for some reason.</CallErrorMessage>
</result>
</m:myOperationResponse>
</env:Body>

У меня есть обходные пути:

  1. Создание и поддержка собственного сериализатора.
  2. Извлечение пространства имен из ответа до десериализации.

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

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

1 Ответ

1 голос
/ 08 февраля 2013

Скорее всего, WSDL не имеет тегов CallSuccessful и CallErrorMessage с правильными пространствами имен, поэтому прокси-класс вашего сервиса не имеет соответствующего пространства имен.

На самом деле вы можете загрузить WSDL, сохранить его в своем проекте, разобраться с пространством имен, как вам нужно, сгенерировать ссылку на службу из этого WSDL (с помощью мастера графического интерфейса или svcutil), указать app.config или web. Конфигурационный файл для фактического веб-службы Java. Вы можете следовать этому процессу каждый раз, когда вам нужно обновить службу.

Надеюсь, это поможет.

...