为了账号安全,请及时绑定邮箱和手机立即绑定

DataContractJsonSerializer 反序列化问题

DataContractJsonSerializer 反序列化问题

C#
慕田峪9158850 2022-01-09 16:12:07
我需要反序列化下面给出的 Json 数组....[    {        "GeoType": 1,        "ID": "2650f7d2-7a5e-4b63-856c-07600fa2a854",        "Name": "Afghanistan",        "CapitalCity": null,        "CountryBoundaries": null,        "CountryCode": "AF",        "ISO": "AFG",        "Parent": {            "__type": "Region:#MEDEX.Library.Geo",            "GeoType": 0,            "ID": "6dc22edb-d711-4253-937f-242b0cd3c011",            "Name": "Asia",            "Code": "Asi"        },        "RegionID": "6dc22edb-d711-4253-937f-242b0cd3c011"    },    {        "GeoType": 1,        "ID": "3917c1c8-ee01-4e9b-8622-0fac9e9194ab",        "Name": "Albania",        "CapitalCity": null,        "CountryBoundaries": null,        "CountryCode": "AL",        "ISO": "ALB",        "Parent": {            "__type": "Region:#MEDEX.Library.Geo",            "GeoType": 0,            "ID": "b7ebd500-45e6-4a48-a2ef-f38fe99e7352",            "Name": "Europe",            "Code": "Eur"        },        "RegionID": "b7ebd500-45e6-4a48-a2ef-f38fe99e7352"    }]我的对象定义是:[DataContract]public class Parent1{    [DataMember]    public Dictionary<string, Type> __type { get; set; }    [DataMember]    public string ID { get; set; }    [DataMember]    public string Name { get; set; }    [DataMember]    public string GeoType { get; set; }    [DataMember]    public string Code { get; set; }}它总是出错:{"元素 ':Parent' 包含映射到名称 ' http://schemas.datacontract.org/2004/07/MEDEX.Library.Geo:Region '的类型的数据。反序列化器不知道任何类型映射到此名称。如果您使用 DataContractSerializer,请考虑使用 DataContractResolver,或者将与“Region”对应的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将其添加到传递给的已知类型列表中序列化程序。"}你能建议我任何解决方案吗?我什至不明白这个错误意味着什么。请建议。
查看完整描述

2 回答

?
撒科打诨

TA贡献1934条经验 获得超2个赞

正如在解释这个答案,以parse.com:SerializationException反序列化JSON与“__type”属性的对象,你的问题是,"__type"是一个保留的属性的DataContractJsonSerializer。它用于识别多态类型的派生类型。从文档:


保留类型信息


为了保留类型标识,在将复杂类型序列化为 JSON 时,可以添加“类型提示”,并且反序列化器会识别该提示并采取适当的行动。“类型提示”是一个 JSON 键/值对,键名为“__type”(两个下划线后跟单词“type”)。该值是“DataContractName:DataContractNamespace”形式的 JSON 字符串(第一个冒号之前的任何内容都是名称)...


类型提示与 XML Schema Instance 标准定义的 xsi:type 属性非常相似,并在序列化/反序列化 XML 时使用。


由于与类型提示的潜在冲突,禁止名为“__type”的数据成员。


因此,您无法手动将此属性添加到您的类中并使其正确翻译。


但是,您可以利用序列化程序对多态性的处理来"__type" 自动读取和写入,方法是定义一个Region类继承自某个基类型的区域的类层次结构,例如RegionBase,由 引用Country.Parent:


[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/MEDEX.Library.Geo")]

public class Country

{

    [DataMember]

    public string ID { get; set; }

    [DataMember]

    public string Name { get; set; }

    [DataMember]

    public string GeoType { get; set; }


    [DataMember]

    public RegionBase Parent { get; set; }


    [DataMember]

    public string RegionID { get; set; }

    [DataMember]

    public string CountryCode { get; set; }

    [DataMember]

    public string ISO { get; set; }

}


[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/MEDEX.Library.Geo")]

[KnownType(typeof(Region))]

public class RegionBase

{

}


[DataContract(

    Name = "Region", 

    Namespace = "http://schemas.datacontract.org/2004/07/MEDEX.Library.Geo")]

public class Region : RegionBase

{

    [DataMember]

    public string ID { get; set; }

    [DataMember]

    public string Name { get; set; }

    [DataMember]

    public string GeoType { get; set; }

    [DataMember]

    public string Code { get; set; }

}

然后反序列化为 a List<Country>,因为您的外部 JSON 容器是一个数组。


笔记:


类型提示的格式为"DataContractName:DataContractNamespace".


此外,如减少类型提示的大小中所述,类型提示中的前缀#是http://schemas.datacontract.org/2004/07/. 因此Region必须具有以下数据合约名称:


[DataContract(

    Name = "Region", 

    Namespace = "http://schemas.datacontract.org/2004/07/MEDEX.Library.Geo")]

我的答案中的类型层次结构足以反序列化示例 JSON,但它可能并不理想。例如,在实践中,可能存在RegionBase与Region(例如ID)共享属性的其他子类型,因此应该将这些属性移至基类。或者可能还有其他可能的子类RegionBase未在您的问题中显示,例如"SomeOtherKindOfRegion:#MEDEX.Library.Geo",需要将其添加到模型中。


由于这个 JSON 似乎来自 WCF 服务,因此希望它已经发布了它的Service Metadata。如果是这样,它将允许您使用Visual Studio 中的添加服务引用自动生成客户端。有关如何执行此操作的说明,请参阅如何:创建 Windows Communication Foundation 客户端和如何:添加、更新或删除服务引用。自动客户端生成应该避免您遇到的困难。


有关这方面的示例,请参阅如何使用 DataContractSerializer 使用未命名的类型集合反序列化 JSON或如何使用 WSDL 文件创建 WCF 服务(不进行调用)。


数据契约序列化程序必须RegionBase通过已知类型机制获知所有可能的多态子类型。


查看完整回答
反对 回复 2022-01-09
?
慕码人2483693

TA贡献1860条经验 获得超9个赞

将 [KnownType(Region)] 添加到类 Parent1 属性


查看完整回答
反对 回复 2022-01-09
  • 2 回答
  • 0 关注
  • 237 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信