具有继承功能的反序列化Newtonsoft JSON.NET无法正常工作

Mar*_*fia 3 c# postgresql json json.net jsonb

(使用Newtonsoft JSON.NET)

嗨,我在反序列化事件列表时遇到了一个问题,其中Event是基本类型,例如ResourceEvent是子类。如果我只是进行序列化然后反序列化,一切正常,并且列表包含ResourceEvents-但是,我将使用EF7的事件存储在postgres的jsonb列中。

当我从postgres获取JSON有效负载时,它已经对属性进行了重新排序(但JSON合法)。当我尝试使用Newtonsoft JSON.net进行反序列化时,它只给我一个包含基本类型Event而不是子类ResourceEvent的列表。

我添加了两个高度剥离的示例,区别在于“ Type”属性在不同位置。在类中还对其他属性的顺序进行了排序。我根本没有在类上的注释。

此有效载荷成功地反硝化:

json
{
    "$type": "System.Collections.Generic.List`1[[Event, Tests]], mscorlib",
    "$values": [
        {
            "$type": "ResourceConfigurationEvent, Tests",
            /* Properties */
            "Resources": {
                /* Properties */                
            },
            "Type": 1            
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

该有效负载未能成功反序列化:

json
{
    "$type": "System.Collections.Generic.List`1[[Event, Tests]], mscorlib",
    "$values": [
        {
            "Type": 1,            
            "$type": "ResourceConfigurationEvent, Tests",
            /* Properties */
            "Resources": {
                /* Properties */                
            },
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*ers 5

Json.Net通常期望$type元数据是每个对象的第一个属性,以实现反序列化的最佳效率。如果$type没有首先出现,则Json.Net会假设它不存在。这就是为什么对属性重新排序时会得到不同结果的原因。

幸运的是,Json.Net提供了一个MetadataPropertyHandling设置来允许它应对这种情况。如果设置MetadataPropertyHandlingReadAhead它应该可以解决您的问题。请注意,这将对性能产生影响。

这是文档中的代码示例

string json = @"{
  'Name': 'James',
  'Password': 'Password1',
  '$type': 'MyNamespace.User, MyAssembly'
}";

object o = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All,
    // $type no longer needs to be first
    MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
});

User u = (User)o;

Console.WriteLine(u.Name);
// James
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!奇迹般有效!我会与 postgres 人员核实他们是否可以在 'jsonb' 列中保留排序。再次非常感谢您的及时答复!:) (2认同)