【发布时间】:2020-06-30 14:08:43
【问题描述】:
.NET Core 2.x 用于生成“普通”XML 格式,可以使用标准方法轻松反序列化,但现在,至少在 v3.1.5 中,在启动配置中使用 AddXmlDataContractSerializerFormatters 来启用 API 返回 XML返回看起来像这样的响应...
<ArrayOfArrayOfKeyValueOfstringanyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<ArrayOfKeyValueOfstringanyType>
<KeyValueOfstringanyType>
<Key>districtId</Key>
<Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:decimal">122</Value>
</KeyValueOfstringanyType>
<KeyValueOfstringanyType>
<Key>amount</Key>
<Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:decimal">1888810.42</Value>
</KeyValueOfstringanyType>
</ArrayOfKeyValueOfstringanyType>
<ArrayOfKeyValueOfstringanyType>
<KeyValueOfstringanyType>
<Key>districtId</Key>
<Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:decimal">205</Value>
</KeyValueOfstringanyType>
<KeyValueOfstringanyType>
<Key>amount</Key>
<Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:decimal">1207736.00</Value>
</KeyValueOfstringanyType>
</ArrayOfKeyValueOfstringanyType>
</ArrayOfArrayOfKeyValueOfstringanyType>
当尝试在客户端代码中反序列化时使用
var serializer = new XmlSerializer(typeof(List<MyDto>));
var reader = new StringReader(content);
var list = (List<MyDto>)serializer.Deserialize(reader);
抛出异常是可以理解的
InvalidOperationException: <ArrayOfArrayOfKeyValueOfstringanyType xmlns='http://schemas.microsoft.com/2003/10/Serialization/Arrays'> was not expected.
本例中使用的 DTO 很简单
public class MyDto
{
public decimal DistrictId { get; set; }
public decimal Amount { get; set; }
}
所以它期待与此类似的 XML,它可以正常工作
<ArrayOfMyDto>
<MyDto>
<DistrictId>122</DistrictId>
<Amount>1888810.42</Amount>
</MyDto>
... more items in list here
</ArrayOfMyDto>
有人知道如何反序列化现在在 .NET Core 3.1.5 中返回的这种 XML 格式吗?
更新:
在我的情况下,真正的问题是我需要反序列化的 XML 看起来确实如此,因为它是 ExpandoObjects 的序列化列表,而不是常规 DTO 的列表,即使常规 DTO 是 expando 对象中的数据源.
对于常规 DTO 列表,我会使用 AddXmlSeralizerFormatters,它会反序列化包含在“ArrayOf”中的 DTO 列表。
我使用 AddXmlSerializerFormatters 和 AddXmlDataContractSerializerFormatters 以及常规 DTO 列表和 ExpandoObjects 列表执行了一系列测试,以确定行为以及在不编写自定义类来反序列化此 XML 响应的情况下可以做什么:
从客户的角度来看:
- AddXmlSerializerFormatters 可以处理常规对象 (DTO) 的常规列表以进行序列化或反序列化
- AddXmlSerializerFormatters 无法处理序列化或反序列化的动态对象 (ExpandoObject) 列表(406 不可接受)
- AddXmlDataContractSerializerFormatters 可以处理常规对象列表 (DTO) 的序列化,但不能处理反序列化 (InvalidOperationException)
- AddXmlDataContractSerializerFormatters 可以处理动态对象 (ExpandoObject) 列表的序列化但不能反序列化 (InvalidOperationException)
- 同时使用两个 Formatter,首先在管道中使用 AddXmlSerializerFormatters,是否允许将序列化和反序列化传递给 AddXmlDataContractSerializerFormatters,因为前者返回 406 Not Acceptable,并且观察到后者的行为
- 同时使用两个格式化程序,首先在管道中使用 AddXmlDataContractSerializerFormatters,不允许此通过,因为返回 InvalidOperationException 并停止处理
从服务器的角度来看:
- AddXmlSerializerFormatters 不能处理常规对象 (DTO) 的 POST(400 错误请求),并且不能传递给可以处理它的 AddXmlDataContractSerializerFormatters
因此,总而言之,无需为“ArrayOf”包装的 XML 编写自定义 DTO 即可预期的最佳行为是在客户端应用程序中使用 AddXmlSerializerFormatters,然后使用 AddXmlDataContractSerializerFormatters,并在服务器应用程序中仅使用 AddXmlDataContractSerializerFormatters
或者更好的是,在您的服务器上完全抛弃 XML 并使用 JSON:P
【问题讨论】:
-
xml 序列化程序不接受列表对象 (List
),因此您应该使用 MyDto。所以你的联系人应该是 ArrayOfKeyValueOfstringanyType 然后你需要两个类 ArrayOfKeyValueOfstringanyType 和 KeyValueOfstringanyType -
我发现确实不能使用 AddXmlDataContractSerializerFormatters 反序列化 DTO 或 ExpandoObject 列表。但是,使用 AddXmlSerializerFormatter 可以处理 DTO 列表而不是 ExpandoObjects 列表,而不使用您建议的自定义类
标签: c# xml serialization .net-core