为什么我的 WCF Web 服务在具有不同字段名称的不同命名空间中显示此对象? [英] Why is my WCF web service presenting this object in a different namespace with different field names?

查看:28
本文介绍了为什么我的 WCF Web 服务在具有不同字段名称的不同命名空间中显示此对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上下文:我正在尝试与 DocuSign 的 Connect 通知服务集成.我已经使用名为 DocuSignConnectUpdate 的方法设置了 WCF 服务,该方法将 DocuSignEnvelopeInformation 作为其唯一参数,如 DocuSign 所指定.这个 DocuSignEnvelopeInformation 对象来自对他们的 API 的引用,因此他们可以传递这个反对我的网络服务,我确切地知道会发生什么.DocuSign 要求提供我在他们网站上配置的服务地址和命名空间.

The Context: I'm trying to integrate with DocuSign's Connect notification service. I've set up a WCF service with a method called DocuSignConnectUpdate which takes a DocuSignEnvelopeInformation as its only parameter, as specified by DocuSign. This DocuSignEnvelopeInformation object comes from a reference to their API, so that they can pass this object to my web service, and I know exactly what to expect. DocuSign asks for my service address and the namespace, which I have configured on their site.

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

The Problem: The XML that DocuSign sends is what I would expect. The DocuSignEnvelopeInformation and its children are in the namespace "http://www.docusign.net/API/3.0" and the element names match the object names:

<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 服务期望得到一些不同的东西,在错误的命名空间中,并且具有修改的元素名称.这是 DocuSignConnectUpdate 方法在我的 WSDL 中的定义方式:

But my web service is expecting something different, in the wrong namespace, and with modified element names. This is how the DocuSignConnectUpdate method is defined in my WSDL:

<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 类型的方式:

And this is how this is how the DocuSignEnvelopeInformation type is defined in my WSDL:

<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 这样的元素名称是自动生成的代码中使用的私有 变量的名称.公共属性名称与 DocuSign 发送的 xml 匹配.自动生成的代码还使用 XmlTypeAttribute 用正确的文档名称空间标记每个对象.因此,从自动生成的代码来看,我希望我的服务对输入感到满意,但生成的 WSDL 不同,如上所示,我的服务无法反序列化 xml.

Element names like envelopeStatusField are the names of the private variables used in the auto-generated code. The public property names match the xml that DocuSign sends. The auto-generated code also tags each object with the correct docusign namespace using XmlTypeAttribute. So from looking at the auto-generated code, I would expect my service to be happy with the input, but the WSDL generated is different, as shown above, and my service fails to deserialize the xml.

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

Some Code: The auto-generated declaration of 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:

The OperationContract for the only method:

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

DocuSign 调用的方法

The method that DocuSign calls

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

       return DocuSignEnvelopeInformation.EnvelopeStatus.EnvelopeID;
    }
}

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

So, again, the question is why is the wsdl showing up this way? Why is the object different from the reference I pulled it from? And more importantly, can I fix it?

推荐答案

我在这件事上花费了多少小时,尝试了多少解决方案,我遵循了多少链接,以及有多少 SO我读过的答案在最终发现答案就在这里之前没有回答我的问题2 年!

It is stunning how many hours I've spent on this, how many solutions I've tried, how many links I've followed, and how many SO answers I've read that did not answer my question before finally finding that the answer was sitting right here on SO for more than 2 years!

根本问题是DocuSignEnvelopeInformation对象默认被DataContractSerializer序列化和反序列化.这实质上是序列化了构成对象的本地命名空间中的私有成员变量,而不是公共属性.令人气愤的是,这是 WCF 服务的默认序列化程序.如果服务应用程序的自动生成代码至少用 [DataContractFormat] 明确地标记了示例方法,我们就会有线索可以遵循,但这只是一个看不见的默认值,您必须以某种方式进行推测.

The root problem is that the DocuSignEnvelopeInformation object is being serialized and deserialized by DataContractSerializer by default. This essentially serializes the private member variables that make up the object in their local namespace instead of the public properties. Infuriatingly, this is the default serializer for WCF services. If the auto-generated code of the service application at least marked the sample methods with [DataContractFormat] explicitly, we would have a clue to follow, but it is just an invisible default that you have to divine somehow.

解决方法是在接口中用[XmlSerializerFormat]标记每个方法.这将 DataContractSerializer 替换为 XmlSerializer 作为方法参数的序列化器:

The solution is to mark each method with [XmlSerializerFormat] in the interface. This replaces DataContractSerializer with XmlSerializer as the serializer for the method parameters:

[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);
}

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

And just like that, the public properties, with their declared namespaces and everything I need, are now serialized instead of the private data!

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

For my specific concern, to receive calls from DocuSign's Connect notification service, I still had one small namespace problem. The root level parameter, the DocuSignEnvelopeInformation, was still in the namespace of the method call. I’m not sure why. For now, I'm just putting the method call itself in the DocuSign API namespace (as you can see in the code sample above). The service now deserializes these calls correctly.

这篇关于为什么我的 WCF Web 服务在具有不同字段名称的不同命名空间中显示此对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆