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

2022-09-03 05:32:07

我的团队的任务是让几个内部开发的 .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 属性。源 = 系统.服务模型

当我检查.NET自动生成的代理类文件Refact.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 样式是文档字面的。在互联网上进行一些研究后,默认情况下似乎有WCF。使用 doc-literal 包装来翻译 WSDL 文件,这可以至少部分解释为什么我们在 WSDL 文件中看到此 WCF 序列化问题。

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

[System.xml.serialization.XmlAttributeAttribute()]

如果我在代理类文件中注释掉了此属性的所有实例并重新运行我的客户端应用,则 SOAP 消息将成功通过网络发送,并且我会收到来自服务器的有效 Web 服务响应。

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

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

或者至少对为什么我们在.NET中看到这种序列化行为与Java WSDL文件的高级描述?

提前致谢,约翰


答案 1

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

这将创建与通过Visual Studio创建的类略有不同的类,这些类由Ladislav Mrnka在这里描述。在客户端使用时,生成的代理应不受 XmlAttribute 问题的影响。

例:

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

答案 2

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

  • 在“服务引用”下打开“引用.svcmap”
  • 在下方添加并保存<Wrapped>true</Wrapped><ClientOptions>
  • 右键单击 Reference.svcmap,然后点击“运行自定义工具”

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

注意:已尝试使用 VS 2015。以前的版本可能具有相同的选项,其名称与“运行自定义工具”不同