为什么我的 WCF Web 服务在具有不同字段名称的不同命名空间中呈现此对象?

2024-04-25

上下文:我正在尝试与 DocuSign 的 Connect 通知服务集成。我已经使用名为 DocuSignConnectUpdate 的方法设置了 WCF 服务,该方法将 DocuSignEnvelopeInformation 作为其唯一参数,如 DocuSign 所指定。此 DocuSignEnvelopeInformation 对象来自对他们的API https://demo.docusign.net/api/3.0/api.asmx,以便他们可以将此对象传递到我的 Web 服务,并且我确切地知道会发生什么。 DocuSign 要求提供我的服务地址和命名空间,这些是我在他们的网站上配置的。

问题:DocuSign 发送的 XML 正是我所期望的。 DocuSignEnvelopeInformation 及其子项位于命名空间“http://www.docusign.net/API/3.0 http://www.docusign.net/API/3.0" 并且元素名称与对象名称匹配:

<DocuSignEnvelopeInformation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.docusign.net/API/3.0">
    <EnvelopeStatus>...</EnvelopeStatus>
</DocuSignEnvelopeInformation>

但我的 Web 服务期望出现不同的情况,在错误的命名空间中,并且元素名称已修改。这就是我的 WSDL 中定义 DocuSignConnectUpdate 方法的方式:

<xs:element name="DocuSignConnectUpdate">
    <xs:complexType>
        <xs:sequence>
            <xs:element minOccurs="0" name="DocuSignEnvelopeInformation" nillable="true" type="tns:DocuSignEnvelopeInformation"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>

这就是我的 WSDL 中定义 DocuSignEnvelopeInformation 类型的方式:

<xs:complexType name="DocuSignEnvelopeInformation">
    <xs:sequence>
        <xs:element xmlns:q1="http://schemas.datacontract.org/2004/07/System.ComponentModel" name="PropertyChanged" nillable="true" type="q1:PropertyChangedEventHandler"/>
        <xs:element name="documentPDFsField" nillable="true" type="tns:ArrayOfDocumentPDF"/>
        <xs:element name="envelopeStatusField" nillable="true" type="tns:EnvelopeStatus"/>
        <xs:element name="timeZoneField" nillable="true" type="xs:string"/>
        <xs:element name="timeZoneOffsetField" type="xs:int"/>
        <xs:element name="timeZoneOffsetFieldSpecified" type="xs:boolean"/>
    </xs:sequence>
</xs:complexType>

像envelopeStatusField这样的元素名称是private自动生成的代码中使用的变量。公共属性名称与 DocuSign 发送的 xml 匹配。自动生成的代码还使用 XmlTypeAttribute 用正确的文档签名命名空间标记每个对象。因此,从查看自动生成的代码来看,我希望我的服务对输入感到满意,但生成的 WSDL 不同,如上所示,并且我的服务无法反序列化 xml。

一些代码:自动生成的 DocuSignEnvelopeInformation 声明:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.17929")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.docusign.net/API/3.0")]
public partial class DocuSignEnvelopeInformation : object, System.ComponentModel.INotifyPropertyChanged {

    private EnvelopeStatus envelopeStatusField;

    private DocumentPDF[] documentPDFsField;

    private string timeZoneField;

    private int timeZoneOffsetField;

    private bool timeZoneOffsetFieldSpecified;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order=0)]
    public EnvelopeStatus EnvelopeStatus {
    ...
    ...

唯一方法的OperationContract:

[SoapHeaders]
[ServiceContract(Namespace = "http:/MyNameSpace")]
public interface IDocusignEventListener
{
    [OperationContract]
    [FaultContract(typeof(ErrorMessageCollection), Action = Constants.FaultAction)]
    string DocuSignConnectUpdate(DocuSignEnvelopeInformation DocuSignEnvelopeInformation);
}

DocuSign调用的方法

[ServiceBehavior(Namespace = "http:/MyNameSpace", ConfigurationName = "DocusignEventListener")]
public class DocusignEventListener : IDocusignEventListener
{
    public string DocuSignConnectUpdate(DocuSignEnvelopeInformation DocuSignEnvelopeInformation)
   {
       ...

       return DocuSignEnvelopeInformation.EnvelopeStatus.EnvelopeID;
    }
}

那么,问题又是为什么 wsdl 会以这种方式显示?为什么该对象与我从中提取它的引用不同?更重要的是,我能修复它吗?


令人震惊的是,我在这上面花了多少时间,尝试了多少解决方案,关注了多少链接,以及在最终找到答案之前阅读了多少没有回答我的问题的答案正在坐着就在这儿 https://stackoverflow.com/a/7492665/2453110已经用了两年多了!

根本问题是 DocuSignEnvelopeInformation 对象默认由 DataContractSerializer 进行序列化和反序列化。这本质上是序列化在其本地命名空间中组成对象的私有成员变量,而不是公共属性。令人恼火的是,这是 WCF 服务的默认序列化程序。如果服务应用程序的自动生成代码至少将示例方法标记为[DataContractFormat]明确地,我们会有一条线索可以遵循,但这只是一个无形的默认值,你必须以某种方式占卜。

解决方案是将每个方法标记为[XmlSerializerFormat]在界面中。这将 DataContractSerializer 替换为 XmlSerializer 作为方法参数的序列化器:

[SoapHeaders]
[ServiceContract(Namespace = "http://www.docusign.net/API/3.0")]
public interface IDocusignEventListener
{
    [OperationContract]
    [XmlSerializerFormat]
    [FaultContract(typeof(ErrorMessageCollection), Action = Constants.FaultAction)]
    string DocuSignConnectUpdate(DocuSignEnvelopeInformation DocuSignEnvelopeInformation);
}

就像这样,公共属性及其声明的命名空间和我需要的一切现在都被序列化,而不是私有数据!

对于我的具体问题,为了接收来自 DocuSign 的 Connect 通知服务的呼叫,我仍然遇到一个小的命名空间问题。根级别参数 DocuSignEnvelopeInformation 仍然位于方法调用的命名空间中。我不知道为什么。目前,我只是将方法调用本身放入 DocuSign API 命名空间中(如上面的代码示例所示)。该服务现在可以正确反序列化这些调用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么我的 WCF Web 服务在具有不同字段名称的不同命名空间中呈现此对象? 的相关文章

随机推荐