Почему мой веб-сервис WCF представляет этот объект в другом пространстве имен с разными именами полей?

Контекст: я пытаюсь интегрироваться с службой уведомления DocuSign Connect. Я установил службу WCF с помощью метода DocuSignConnectUpdate, который принимает параметр DocuSignEnvelopeInformation как единственный параметр, определенный DocuSign. Этот объект DocuSignEnvelopeInformation исходит из ссылки на их API , так что они могут передать этот объект моей веб-службе, и я точно знаю, чего ожидать. DocuSign запрашивает мой служебный адрес и пространство имен, которое я настроил на их сайте.

Проблема: XML, который отправляет DocuSign, я ожидаю. DocuSignEnvelopeInformation и ее дочерние элементы находятся в пространстве имен « http://www.docusign.net/API/3.0 », а имена элементов соответствуют именам объектов:

 ...  

Но мой веб-сервис ожидает чего-то другого, в неправильном пространстве имен и с измененными именами элементов. Именно так определяется метод DocuSignConnectUpdate в моем WSDL:

        

И именно так определяется тип DocuSignEnvelopeInformation в моем WSDL:

           

Имена элементов, такие как envelopeStatusField, – это имена частных переменных, используемых в автоматически сгенерированном коде. Имена публичной собственности соответствуют xml, который отправляет DocuSign. Автоматически сгенерированный код также маркирует каждый объект с правильным пространством имен docusign, используя 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; ///  [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 появляется таким образом? Почему объект отличается от ссылки, с которой я его вытащил? И что еще более важно, могу ли я исправить это?

Потрясающе, сколько часов я потратил на это, сколько решений я пробовал, сколько ссылок я следил и сколько ответов SO, которые я прочитал, которые не отвечали на мой вопрос, прежде чем, наконец, выяснив, что ответ сидел прямо здесь, на SO более двух лет!

Корневая проблема заключается в том, что объект 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); } 

И так же, публичные свойства, с их объявленными пространствами имен и всем, что мне нужно, теперь сериализуются вместо частных данных!

Для моей особой озабоченности, чтобы получать звонки от службы уведомлений ConnectS DocuSign, у меня все еще была одна небольшая проблема с пространством имен. Параметр корневого уровня, DocuSignEnvelopeInformation, все еще находился в пространстве имен вызова метода. Я не знаю, почему. На данный момент я просто помещаю вызов метода в пространство имен DocuSign API (как вы можете видеть в примере кода выше). Служба теперь десериализирует эти вызовы правильно.

  • Как выбрать узлы XML с пространствами имен XML из XmlDocument?
  • Как XPath обрабатывает пространства имен XML?
  • Xml пространство имен, разбивающее мой xpath!
  • Как сериализовать объект в XML без получения xmlns = "..."?
  • Невозможно добавить пространство имен в атрибут с помощью SimpleXML PHP
  • Какое пространство имен XML используется с JSF 2.2
  • XDocument, содержащий пространства имен
  • Давайте будем гением компьютера.