Newtonsoft中的TypeNameHandling需要$ type作为第一个属性吗?

时间:2013-03-22 12:36:55

标签: serialization backbone.js asp.net-mvc-4 asp.net-web-api json.net

我的web api中有以下方法

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

我正在使用骨干js使用fiddler将以下JSON发送到服务器,值为null:

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

但是如果我首先在JSON对象中添加$ type属性,则反序列化工作正常,请参阅:

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

是否可以配置newtonsoft以检查对象中任何位置的$ type属性而不是第一个属性,还是可以配置骨干,以便它始终首先在JSON对象中添加$type属性?

4 个答案:

答案 0 :(得分:4)

我强烈建议不要配置任何序列化程序(包括JSON.NET)来从传入的有效负载中读取对象类型。这在历史上一直是Web应用程序中存在大量漏洞的原因。相反,将公共入口点更改为您的操作以将实际类型作为绑定参数,然后根据需要委托给内部可测试方法。

答案 1 :(得分:3)

首先,AFAIK,Json.NET的代码经过优化,以避免将整个对象保存在内存中,只是为了读取它的类型。因此,最好将$type作为第一个属性。

其次,您可以编写自己的JsonConverter,首先读取JObject(使用Load方法),手动读取$type属性,从序列化程序的{{1获取类型,创建值并从SerializationBinder填充它。

第三,关于安全性。虽然Json.NET的JObject可能听起来不错,但通常不是。它允许Json.NET通过在JSON文件中编写其类型,从任何程序集创建任何对象类型。最好将自定义$type与字典一起使用,该字典只允许您指定的类型。您可以在我的私有框架中找到一个示例(它还支持从SerializationBinder获取$type的值):

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

(这个版本使用了其他类中的一些方法,但它们很简单。后来的提交使得类更复杂。)

答案 2 :(得分:1)

这将在骨干网中起作用,但我不知道每个浏览器的行为是否相同。基本上,并不能保证每个浏览器都会按照添加的顺序保留项目。


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;
  }


});

你最好让NewtonSoft的JSON解串器工作,而不需要它在特定的位置。希望这是可能的。

答案 3 :(得分:1)

我显然有同样的问题,有人找到答案。不确定分享答案并给予他所有信用的适当方式,但这是链接: Newtonsoft JSON.net deserialization error where fields in JSON change order

这就是那个人: https://stackoverflow.com/users/3744182/dbc