.NET Core 3.1 API接受复杂的XML对象



编辑

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对象不再为null,但它内部的所有内容都为null。

我不知道如何正确处理这个问题。我缺了什么吗?

我的控制器看起来像这个

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

您还需要为Object2Object3设置DataContractAttribute.Namespace

[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.namespace)都映射到命名空间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>    
    

    从中可以看出,用于Object2Object3的元素的名称空间d2p1:是错误的。(此处选择的精确名称空间http://schemas.datacontract.org/2004/07/将取决于您的模型的CLR名称空间,该名称空间在您的问题中没有显示。)

    演示小提琴#3在这里。

  • 您的XML元素没有z:Id="xxx"z:ref="xxx"属性,因此我认为没有必要启用IsReference引用跟踪机制。

相关内容

  • 没有找到相关文章