WCF客户端/ Java Web服务 - 反序列化对象为空

问题描述:

我正在尝试将Java Web服务集成到我的C#项目中。 Web服务由我公司的另一个部门维护,并且不受我的控制。WCF客户端/ Java Web服务 - 反序列化对象为空

我已经创建了一个服务引用,我可以调用该服务。问题是所有的响应对象的属性都是空的。 SOAP响应从服务器返回,但它没有得到正确的反序列化。没有错误报告或记录。

这似乎是一个相当普遍的问题,常见的答案是有一个名称空间不匹配。我相信这也是我的问题,但我很难纠正它。

该Web服务是私人的。我试图把说明问题的一个样本放在一起。下面是相关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序列化类,发现它是一个命名空间问题。下面的代码节选自deserialzer:

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)) { 
    { 
     [email protected] = 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,请告诉我,我会看看我能做些什么。

+0

这是为什么用Java标记的? – Perception

+0

@Perception:Web服务是一个Java Web服务。这种互操作性问题似乎相当普遍,所以我认为一些Java开发人员可能会提供一些见解。这是我的第一个问题,所以也许我对标签有点过分了。 –

+0

我发现与rpc /编码服务和复杂类型命名空间的根本问题。我在这里问了一个更详细的问题:[link](http://stackoverflow.com/questions/7840665/wcf-client-soap-encoding-complex-types-in-different-namespace) –

最有可能的WSDL没有CallSuccessful和CallErrorMessage标签的正确名称空间,这就是为什么您的服务代理类没有适当的名称空间。

实际上,您可以下载WSDL,将其保存在项目中,处理需要的名称空间,通过此WSDL生成服务引用(通过使用GUI向导或svcutil),指向app.config或web .config文件到实际的java web服务。每次需要更新服务时,您都可以按照此过程进行操作。

希望这会有所帮助。