WCF получает пустую модель из XML - PullRequest
0 голосов
/ 13 июня 2018

У нас есть служба WCF с определенным классом (класс был автоматически сгенерирован из XML с использованием http://xmltocsharp.azurewebsites.net/):

namespace CRMtoQLM.DAL
{
    [Serializable]
    [DataContract(Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    public class Envelope
    {
    [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    [DataMember]
    public Body Body { get; set; }
    [XmlAttribute(AttributeName = "soapenv", Namespace = "http://www.w3.org/2000/xmlns/")]
    [DataMember]
    public string Soapenv { get; set; }
    [XmlAttribute(AttributeName = "xsd", Namespace = "http://www.w3.org/2000/xmlns/")]
    [DataMember]
    public string Xsd { get; set; }
    [XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
    [DataMember]
    public string Xsi { get; set; }
}

//[Serializable]
[XmlRoot(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
[DataContract(Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Body
{
    [XmlElement(ElementName = "notifications", Namespace = "http://soap.sforce.com/2005/09/outbound")]
    [DataMember]
    public Notifications Notifications { get; set; }
}

//[Serializable]
[XmlRoot(ElementName = "notifications", Namespace = "http://soap.sforce.com/2005/09/outbound")]
[DataContract(Namespace = "http://soap.sforce.com/2005/09/outbound")]
public class Notifications
{
    [XmlElement(ElementName = "OrganizationId", Namespace = "http://soap.sforce.com/2005/09/outbound")]
    [DataMember]
    public string OrganizationId { get; set; }
    [XmlElement(ElementName = "ActionId", Namespace = "http://soap.sforce.com/2005/09/outbound")]
    [DataMember]
    public string ActionId { get; set; }
    [XmlElement(ElementName = "SessionId", Namespace = "http://soap.sforce.com/2005/09/outbound")]
    [DataMember]
    public string SessionId { get; set; }
    [XmlElement(ElementName = "EnterpriseUrl", Namespace = "http://soap.sforce.com/2005/09/outbound")]
    [DataMember]
    public string EnterpriseUrl { get; set; }
    [XmlElement(ElementName = "PartnerUrl", Namespace = "http://soap.sforce.com/2005/09/outbound")]
    [DataMember]
    public string PartnerUrl { get; set; }
    [XmlElement(ElementName = "Notification", Namespace = "http://soap.sforce.com/2005/09/outbound")]
    [DataMember]
    public Notification Notification { get; set; }
    [XmlAttribute(AttributeName = "xmlns")]
    [DataMember]
    public string Xmlns { get; set; }
}

//[Serializable]
[XmlRoot(ElementName = "Notification", Namespace = "http://soap.sforce.com/2005/09/outbound")]
[DataContract(Namespace = "http://soap.sforce.com/2005/09/outbound")]
public class Notification
{
    [XmlElement(ElementName = "Id", Namespace = "http://soap.sforce.com/2005/09/outbound")]
    [DataMember]
    public string Id { get; set; }
    [XmlElement(ElementName = "sObject", Namespace = "http://soap.sforce.com/2005/09/outbound")]
    [DataMember]
    public SObject SObject { get; set; }
}

//[Serializable]
[XmlRoot(ElementName = "sObject", Namespace = "http://soap.sforce.com/2005/09/outbound")]
[DataContract(Namespace = "http://soap.sforce.com/2005/09/outbound")]
public class SObject
{
    [XmlElement(ElementName = "Id", Namespace = "urn:sobject.enterprise.soap.sforce.com")]
    [DataMember]
    public string Id { get; set; }
    [XmlElement(ElementName = "Asset_Account_City__c", Namespace = "urn:sobject.enterprise.soap.sforce.com")]
    [DataMember]
    public string Asset_Account_City__c { get; set; }
    [XmlElement(ElementName = "Asset_Account_Country__c", Namespace = "urn:sobject.enterprise.soap.sforce.com")]
    [DataMember]
    public string Asset_Account_Country__c { get; set; }
    [XmlElement(ElementName = "Asset_Account_Name__c", Namespace = "urn:sobject.enterprise.soap.sforce.com")]
    [DataMember]
    public string Asset_Account_Name__c { get; set; }
    [XmlElement(ElementName = "Asset_Customer_ID__c", Namespace = "urn:sobject.enterprise.soap.sforce.com")]
    [DataMember]
    public string Asset_Customer_ID__c { get; set; }
    [XmlElement(ElementName = "Expiration_Date__c", Namespace = "urn:sobject.enterprise.soap.sforce.com")]
    [DataMember]
    public string Expiration_Date__c { get; set; }
    [XmlElement(ElementName = "License__c", Namespace = "urn:sobject.enterprise.soap.sforce.com")]
    [DataMember]
    public string License__c { get; set; }
    [XmlElement(ElementName = "Reader_Code__c", Namespace = "urn:sobject.enterprise.soap.sforce.com")]
    [DataMember]
    public string Reader_Code__c { get; set; }
    [XmlElement(ElementName = "Reader_Quantity__c", Namespace = "urn:sobject.enterprise.soap.sforce.com")]
    [DataMember]
    public string Reader_Quantity__c { get; set; }
    [XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
    [DataMember]
    public string Type { get; set; }
    [XmlAttribute(AttributeName = "sf", Namespace = "http://www.w3.org/2000/xmlns/")]
    [DataMember]
    public string Sf { get; set; }
}
}

IService.cs определен так:

    [OperationContract]
    [WebInvoke(Method = "POST",
    UriTemplate = "Test",
    RequestFormat = WebMessageFormat.Xml)]
    //[XmlSerializerFormat]
    string Test(Envelope parameter);

и реализация:

    public string Test(Envelope parameter)
    {
        return "";
    }

, но "параметр" в функции Test содержит объекты NULL.Я знаю, что есть проблема с десериализацией XML, но не могу понять, где именно.

РЕДАКТИРОВАТЬ: это запрос, который я отправляю через Почтальон

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<notifications xmlns="http://soap.sforce.com/2005/09/outbound">
<OrganizationId>123456</OrganizationId>
<ActionId>123456</ActionId>
<SessionId>123456</SessionId>
<EnterpriseUrl>https://eu8.salesforce.com/</EnterpriseUrl>
<PartnerUrl>https://eu8.salesforce.com/</PartnerUrl>
<Notification>
<Id>123456</Id>
<sObject xsi:type="sf:Asset" xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
 <sf:Id>123456</sf:Id>
 <sf:Asset_Account_City__c>123456</sf:Asset_Account_City__c>
 <sf:Asset_Account_Country__c>123456</sf:Asset_Account_Country__c>
 <sf:Asset_Account_Name__c>123456</sf:Asset_Account_Name__c>
 <sf:Asset_Customer_ID__c>123456</sf:Asset_Customer_ID__c>
 <sf:Expiration_Date__c>123456</sf:Expiration_Date__c>
 <sf:License__c>123456</sf:License__c>
 <sf:Reader_Code__c>123456</sf:Reader_Code__c>
 <sf:Reader_Quantity__c>123456</sf:Reader_Quantity__c>
</sObject>
</Notification>
</notifications>
</soapenv:Body>
</soapenv:Envelope>

1 Ответ

0 голосов
/ 14 июня 2018

Привязки на основе SOAP распаковывают конверт SOAP, поэтому вам не нужно определять типы конвертов SOAP.WebHttpBinding, который, как вы говорите, используете, который ничего не знает о SOAP, будет ожидать, что тип контракта (аргумент метода службы IService.Test) будет соответствовать всему телу HTTP, поэтому я вижу логику того, чтовы делаете, однако я не думаю, что нужно работать против такой инфраструктуры.

Чтобы исправить этот сценарий, сделайте пару вещей:

  • измените вашу реализациюIService.Test для получения аргумента типа Notifications
    • string Test(Notifications notifications)
  • изменить конфигурацию службы, указав привязку SOAP на основе HTTP, возможно BasicHttpBinding
    • <endpoint address="/relativeaddress/" binding="basicHttpBinding" ... />
  • Я думаю, что привязка SOAP, вероятно, будет игнорировать WebInvokeAttribute, но для большей безопасности удалите ее.Для связывания SOAP это излишне, потому что SOAP всегда POST.

Не думаю, что вам нужно удалять типы Envelope и Body, но они ничего не сделают, если онине указано, что вы хотите.Привязки WCF изначально понимают конверт SOAP и не нуждаются в его указании; для этого необходимо предоставить типы элемента Body SOAP.

Ваш образец XML содержит один экземпляр Notificationв Notifications, но название подразумевает, что этот дочерний элемент может повторяться - если это так, я не думаю, что сгенерированные классы будут работать для вас, потому что класс Notifications имеет единственное свойство Notification - генератор, который вы связалиу меня нет возможности узнать это, так что я ни в чем не виноват.Я добавил копию элемента Notification в качестве одноуровневого элемента и снова запустил его - на этот раз он сгенерировал элемент списка:

[XmlElement(ElementName="Notification", Namespace="http://soap.sforce.com/2005/09/outbound")]
public List<Notification> Notification { get; set; }

Вы можете использовать инструмент xsd.exe, поставляемый с Visual Studio (яподумайте) для генерации классов - см. документацию .Я не удивлюсь, если этот веб-инструмент управляет этим за кулисами, но я бы доверял xsd.exe в создании классов, которые наилучшим образом соответствовали бы ожиданиям WCF.

...