Newtonsoft.Json, Populate Dictionary failed

前端 未结 1 773
礼貌的吻别
礼貌的吻别 2021-01-20 07:55

I serialize a dictionary to json by Newtonsoft.json and bellow code :

var serializeSettings = new JsonSerializerSettings
        {
            TypeNameHandli         


        
相关标签:
1条回答
  • 2021-01-20 08:27

    The problem is that you have specified TypeNameHandling = TypeNameHandling.All when serializing your dictionary. This causes a metadata "$type" property to be emitted as the first object in the dictionary:

    {
      "$type": "System.Collections.Generic.Dictionary`2[[System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
      "9648af76-7986-4b34-8b2c-97b2345769ef": "Test"
    }
    

    When deserializing using DeserializeObject, this token is normally consumed by Json.NET when the corresponding c# object is constructed. But you are using PopulateObject on a pre-allocated dictionary. Thus the metadata property is not consumed during construction and instead Json.NET tries to add it to the dictionary, and fails.

    The solution is to set MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead in deserializeSettings. Doing so will cause the "$type" property to be consumed or ignored (as appropriate) unconditionally:

    var deserializeSettings = new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.All,
        TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
        Formatting = Formatting.Indented,
        MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
    };
    JsonConvert.PopulateObject(serializedObject, newDic, deserializeSettings);
    

    Please note that, from the release notes, there is a slight cost in memory usage and speed from using this setting.

    Alternatively, if you don't unconditionally need metadata type information in your JSON, you could serialize with TypeNameHandling = TypeNameHandling.Auto and only emit type information for polymorphic types, which your Dictionary<Guid, string> is not.

    Relatedly, when using TypeNameHandling, do take note of this caution from the Newtonsoft docs:

    TypeNameHandling should be used with caution when your application deserializes JSON from an external source. Incoming types should be validated with a custom SerializationBinder when deserializing with a value other than None.

    For a discussion of why this may be necessary, see TypeNameHandling caution in Newtonsoft Json.

    0 讨论(0)
提交回复
热议问题