TypeNameHandling in Newtonsoft requires $type to be the first property? [duplicate]

社会主义新天地 提交于 2019-12-23 09:11:20

问题


I have the following method in my web api

public void Put(string id, [FromBody]IContent value) {
    //Do stuff
}

I'm using backbone js to send the following JSON to the server using fiddler the value is null:

{
    "id": "articles/1",
    "heading": "Bar",
    "$type": "BrickPile.Samples.Models.Article, BrickPile.Samples"
}

but if I add the $type property first in the JSON object the deserialization works fine, see:

{
 "$type": "BrickPile.Samples.Models.Article, BrickPile.Samples",
  "id": "articles/1",
  "heading": "Bar" 
}

is it possible to configure newtonsoft to check for the $type property anywhere in the object instead of the first property or can I configure backbone so it always adds the $type property first in the JSON object?


回答1:


This will work in backbone, but I don't know if every browser will behave the same. There's no guarantee, basically, that every browser will keep the items in the order which they are added.


MyModel = Backbone.Model.extend({

  // ...

  toJSON: function(){
    // build the "$type" as the first parameter
    var json = {"$type": "BrickPile.Samples.Models.Article, BrickPile.Samples"};
    // get the rest of the data
    _.extend(json, Backbone.Model.prototype.toJSON.call(this));
    // send it back, and hope it's in the right order
    return json;
  }


});

You're better of getting NewtonSoft's JSON deserializer to work without needing it in a specific position, though. Hopefully that will be possible.




回答2:


I would very strongly recommend against configuring any serializer (including JSON.NET) to read the object type from the incoming payload. This has historically been the cause of a large number of vulnerabilities in web applications. Instead, change the public entry point to your action to take the actual type as a bound parameter, then delegate to an internal testable method if desired.




回答3:


First, AFAIK, the code of Json.NET is optimized to avoid holding the whole object in memory just to read its type. So it's better to place $type as the first property.

Second, you can write your own JsonConverter which reads first to JObject (using Load method), manually reads $type property, gets type from serializer's SerializationBinder, creates the value and populates it from JObject.

Third, regarding security. While Json.NET's $type may sound like a good idea, it's often not. It allows Json.NET to create any object type from any assembly just by writing its type in JSON file. It's better to use custom SerializationBinder with a dictionary which allows only types which you specify. You can find an example in my private framework (it also supports getting values for $type from JsonObjectAttribute):

https://github.com/Athari/Alba.Framework/blob/742ff1aeeb114179a16ca42667781944b26f3815/Alba.Framework/Serialization/DictionarySerializationBinder.cs

(This version uses some methods from other classes, but they're trivial. Later commits made the class more complex.)




回答4:


I had kind of the same question apparently, and someone found an answer. Not sure whats the appropriate way to share an answer and give him ALL the credit, but this is the link: Newtonsoft JSON.net deserialization error where fields in JSON change order

and this is the guy: https://stackoverflow.com/users/3744182/dbc



来源:https://stackoverflow.com/questions/15570510/typenamehandling-in-newtonsoft-requires-type-to-be-the-first-property

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!