Java工具创建的WSDL文件的WCF序列化问题

Posted

技术标签:

【中文标题】Java工具创建的WSDL文件的WCF序列化问题【英文标题】:WCF Serialization problems with WSDL file created by Java tools 【发布时间】:2011-04-19 22:43:23 【问题描述】:

我的团队的任务是让几个内部开发的 .NET 客户端应用程序连接到一些新的 Java Web 服务。 Java Web 服务是第三方供应商提供的 WSDL 文件,我们的团队对其修改/控制的能力有限......这意味着我们可能有权要求我们的供应商对 WSDL 进行轻微调整,但可能会进行重大更改要么不可行,要么难以请求。

也就是说,我们正在尝试利用 WCF/.NET 4.0 来生成我们在客户端需要的 .NET 代理类文件。代理客户端类文件生成过程执行没有问题。

问题是当我们尝试在客户端应用程序中使用代理类文件时。我已通过 Web 跟踪工具 Fiddler 验证原始 SOAP 消息请求无法通过线路发送到服务器。

我在尝试调用有问题的 Web 服务方法时收到的特定 .NET 异常消息如下所示:

System.InvalidOperationException 未处理 Message=XmlSerializer 属性 System.Xml.Serialization.XmlAttributeAttribute 在 baseLanguage 中无效。当 IsWrapped 为 true 时,仅支持 XmlElement、XmlArray、XmlArrayItem、XmlAnyAttribute 和 XmlAnyElement 属性。 Source=System.ServiceModel

当我检查 .NET 自动生成的代理类文件 Reference.cs 时,我注意到我的 Web 服务方法的请求和响应消息如下所示:

[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。翻译带有 doc-literal 包装的 WSDL 文件,这至少可以部分解释为什么我们会在 WSDL 文件中看到这个 WCF 序列化问题。

通过反复试验,我发现代理类文件中的以下属性装饰器是序列化问题的罪魁祸首:

[System.Xml.Serialization.XmlAttributeAttribute()]

如果我在代理类文件中注释掉该属性的所有实例并重新运行我的客户端应用程序,那么 SOAP 消息就会成功地通过网络发送,并且我会从服务器返回一个有效的 Web 服务响应。

这个修复总比没有好,但我更喜欢不需要我自己或我团队中的任何人不断调整这些 .NET 自动生成的代理类文件的解决方案。

我想知道我是否可以通过各种 WCF 工具或修改 WSDL 文件来阻止 [System.Xml.Serialization.XmlAttributeAttribute()] 应用于我的请求和响应对象属性?

或者至少是对我们在 .NET 中使用 Java WSDL 文件看到这种序列化行为的原因的高级描述?

提前致谢, 约翰

【问题讨论】:

XmlAttributeAttribute 是由您添加还是由 WCF 生成? XMLAttributeAttribute 是由 WCF 工具生成的,我不明白为什么。如果工具中有某种开关来防止它被创建,或者我们可以在源 WSDL 文件中更改某些东西,我们可以避免调整代理类文件以使其工作。 您是否有来自 Java 供应商的示例工作肥皂请求? 【参考方案1】:

使用带有 /wrapped 选项的 svcutil.exe 实用程序来生成代理类。

这将创建与通过 Visual Studio 以 Ladislav Mrnka 描述的方式创建的类略有不同的类。在客户端使用时,生成的代理应该没有 XmlAttribute 问题。

例子:

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

【讨论】:

【参考方案2】:

这是如何在 IDE 中执行 Mikhail G 的解决方案:

在 Service References 下打开 Reference.svcmap 在<ClientOptions> 下添加<Wrapped>true</Wrapped> 并保存 右键单击 Reference.svcmap 并点击“运行自定义工具”

Visual Studio,魔法发生的地方:)

注意:在 VS 2015 上尝试过。之前的版本可能具有相同的选项 不同于“运行自定义工具”的名称

【讨论】:

【参考方案3】:

作为 Stratovarius 回答的后续,在 VS 2017 中,Service References 文件夹已替换为 Connected Services,因此您必须:

    在 Windows 资源管理器中打开 project/Connected Services 文件夹 使用文本编辑器查找和编辑 Reference.svcmap 将<Wrapped>true</Wrapped> 添加到<ClientOptions> 部分 保存文件 在VS中,右键点击Connected Services下的服务引用,选择“更新服务引用”

这从我的服务调用中清除了异常。

【讨论】:

当我选择“更新服务参考”时,VS 2017 (15.9.6) 会自动从 .svcmap 文件中删除 true。是vs2017的bug吗?【参考方案4】:

根据生成的代码,您的 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;  
     

【讨论】:

Laislav,感谢您的评论,但我真正想要的是一种解决方案,我根本不需要接触代理类文件来使 Web 服务正常工作。如果我从代理类文件中注释掉 [XmlAttribute()] 的所有实例,Web 服务就会工作。 但在这种情况下,所有这些参数都作为元素传输。那么你需要这些参数吗?如果不是简单地从 WSDL 中删除它们并重新生成代理。【参考方案5】:

我在我的 .Net Core 应用程序中使用外部“旧”Java 生成的 WSDL,而自动生成的 Reference.cs 对我不起作用。我必须删除 [System.Xml.Serialization.XmlAttributeAttribute()] 才能让它工作。

【讨论】:

以上是关于Java工具创建的WSDL文件的WCF序列化问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 WSDL 文件创建 WCF 代理?

一个 WCF 服务——两个客户端;一个客户端不工作

WCF 生成的 wsdl 与为创建 WCF 服务而提供的原始 wsdl 不同?

WCF服务中的wsdl文件在哪里

配置WCF同时支持WSDL和REST,swaggerwcf生成文档

怎么用cxf的wsdl2java解析wcf生成的wsdl