#c# #xml #api #asp.net-core-3.1 #datacontractserializer
Вопрос:
Редактировать
Ввод XML будет выглядеть следующим образом
<?xml version="1.0" encoding="UTF-8"?>
<Object1>
<field1>Hello</field1>
<field2>
<field3>World</field3>
<field4>
<field5>Test</field5>
<field6>Test2</field6>
</field4>
</field2>
</Object1>
Я немного зациклился на том, как заставить мой API принимать сложный XML-объект
Например, у меня есть такой класс
public class Object1
{
public string field1 {get; set;}
public Object2 field2 {get; set;}
}
public class Object2
{
public string field3 {get; set;}
public Object3 field4 {get; set;}
}
public class Object3
{
public string field5 {get; set;}
public string field6 {get; set;}
}
В моем файле startup.cs я добавил это
services.AddControllers().AddXmlDataContractSerializerFormatters()
.AddXmlSerializerFormatters();
Затем я получил сообщение об ошибке, что он не смог десериализовать ввод.
Поэтому я добавил эти атрибуты к объекту
[DataContract(Namespace = "")]
[XmlRoot]
public class Object1
{
[DataMember(Name = "field1")]
public string field1 {get; set;}
[DataMember(Name = "field2")]
public Object2 field2 {get; set;}
}
[DataContract(Name = "field2", IsReference = true)]
public class Object2
{
[DataMember(Name = "field3")]
public string field3 {get; set;}
[DataMember(Name = "field4")]
public Object3 field4 {get; set;}
}
[DataContract(Name = "field3", IsReference = true)]
public class Object3
{
[DataMember(Name = "field5")]
public string field5 {get; set;}
[DataMember(Name = "field6")]
public string field6 {get; set;}
}
Так что теперь, когда я отправляю XML-объект, над ним можно немного поработать. Я могу получить значение field1, и похоже, что объект field2 больше не является нулевым, но все внутри него равно нулю.
Я не уверен, как подойти к этому правильно. Чего-нибудь мне не хватает?
Мой контроллер выглядит так
[HttpPost]
[Consumes("application/xml")]
public async Task<IActionResult> UpdateObject([FromBody]Object1 object1)
{
var testObject1 = object1.field1; // this value is not null because it is a string datatype and not like the one below which is slightly more complex
var testObject2 = object1.field2; //this is not null but the properties inside the object are null
}
Ответ №1:
Вам нужно установить DataContractAttribute.Namespace
для Object2
и Object3
также:
[DataContract(Namespace = "", Name = "field2", IsReference = true)]
public class Object2
{
[DataMember(Name = "field3")]
public string field3 {get; set;}
[DataMember(Name = "field4")]
public Object3 field4 {get; set;}
}
[DataContract(Namespace = "", Name = "field3", IsReference = true)]
public class Object3
{
[DataMember(Name = "field5")]
public string field5 {get; set;}
[DataMember(Name = "field6")]
public string field6 {get; set;}
}
Демонстрационная скрипка №1 здесь.
Примечания:
- С помощью сериализатора контрактов на данные, если вы явно не указываете пространство имен для объекта контракта на данные, назначается значение по умолчанию, как описано в документах:
По умолчанию контрактам данных для определенного типа назначается пространство имен, которое происходит из пространства имен среды CLR этого типа.
По умолчанию любое заданное пространство имен CLR (в формате Clr.Пространство имен) сопоставляется с пространством
http://schemas.datacontract.org/2004/07/Clr.Namespace
имен . - Логика пространства имен по умолчанию
DataContractSerializer
отличается отXmlSerializer
. Объекты по умолчанию не назначаются пространствуXmlSerializer
имен , поэтому ваша исходная модель работает как есть с этим сериализатором. Демонстрационная скрипка №2 здесь.Если бы вы предпочли использовать
XmlSerializer
вместоDataContractSerializer
«Я верю», вы могли бы удалитьAddXmlDataContractSerializerFormatters()
только «оставитьAddXmlSerializerFormatters()
«. - Простой способ отладить проблемы с десериализацией—сериализовать вашу модель и сравнить фактические результаты с контентом, который вы пытаетесь десериализовать. Если я попытаюсь сериализовать экземпляр вашей текущей
Object1
модели, я получу:<?xml version="1.0" encoding="utf-16"?> <Object1 xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <field1>Hello</field1> <field2 xmlns:d2p1="http://schemas.datacontract.org/2004/07/" z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"> <d2p1:field3>World</d2p1:field3> <d2p1:field4 z:Id="i2"> <d2p1:field5>Test</d2p1:field5> <d2p1:field6>Test2</d2p1:field6> </d2p1:field4> </field2> </Object1>
Из чего видно, что пространство
d2p1:
имен для элементовObject2
иObject3
неверно. (Точное выбранное здесь пространствоhttp://schemas.datacontract.org/2004/07/
имен будет зависеть от пространства имен CLR вашей модели, которое не указано в вашем вопросе.)Демонстрационная скрипка №3 здесь.
- Ваши XML-элементы не имеют
z:Id="xxx"
z:ref="xxx"
атрибутов или, поэтому я не вижу необходимости включатьIsReference
механизм отслеживания ссылок.
Комментарии:
1. Спасибо вам за этот вклад! Я не знал, что мне нужно также указать пространство имен для всех других объектов! Большое вам спасибо за это разъяснение!