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

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

问题描述

上下文:我正在尝试与DocuSign的Connect通知服务集成。我已经使用称为DocuSignConnectUpdate的方法设置了WCF服务,该方法将DocuSignEnvelopeInformation作为其唯一参数(由DocuSign指定)。此DocuSignEnvelopeInformation对象来自对其API 的引用,以便他们可以通过此反对我的Web服务,我确切知道会发生什么。 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服务期望使用错误的名称空间并修改了元素名称的情况有所不同。这是在我的WSDL中定义DocuSignConnectUpdate方法的方式:

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)是在变量中使用的 private 变量的名称。自动生成的代码。公共属性名称与DocuSign发送的xml匹配。自动生成的代码还会使用XmlTypeAttribute用正确的docusign命名空间标记每个对象。因此,从查看自动生成的代码开始,我希望我的服务对输入感到满意,但是生成的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答案,但都没有回答我的问题,最后才发现答案在就在这里在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!

根本问题是DataContractSerializer正在对DocuSignEnvelopeInformation对象进行序列化和反序列化默认情况下。这实际上是序列化组成对象的私有成员变量,这些变量在其本地名称空间中而不是公共属性中。令人震惊的是,这是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] 标记每个方法。这将用XmlSerializer代替DataContractSerializer作为方法参数的序列化器:

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天全站免登陆