Newtonsoft.Json

创建时间:
2014-03-10 20:59
最近更新:
2018-10-21 15:48

Brief

Official Website

Install (NuGet)

https://www.nuget.org/packages/Newtonsoft.Json/ - PM> Install-Package Newtonsoft.Json.
Authors: James Newton-King

Visual Studio 2013 中 .NET Framework 4.5.1 的 WebAPI 与 MVC 的项目模板的 NuGet 的 "packages" 文件夹中已自带了 "Newtonsoft.Json.dll"。

Visual Studio 2013 项目中实际引用的 DLL 的名称为 Newtonsoft.Json.dll

常用 API

  1. JsonConvert.SerializeObject Method
  2. Formatting Enumeration - None & Indented (缩进)

LINQ to JSON

  1. Newtonsoft.Json.Linq Namespace - The Newtonsoft.Json.Linq namespace provides classes that are used to implement LINQ to JSON.
  2. Newtonsoft.Json.Linq.JToken 类
  3. Newtonsoft.Json.Linq.JObject 类
  4. Newtonsoft.Json.Linq.JArray 类
  5. Newtonsoft.Json.Linq.JValue 类
  6. Newtonsoft.Json.Linq.JProperty 类
  7. Newtonsoft.Json.Linq.JRaw 类
  8. Newtonsoft.Json.Linq.Extensions 类
  9. JTokenType Enumeration 类

LINQ to JSON - 官网相关 Samples 的读书笔记

var jA = new JArray();
jA.Add(any type);

var jO = new JObject();
jO["MyArray"] = jA;

string json = o.ToString();
var jO = new JObject {
    { "Cpu", "Intel" },
    { "Memory", 32 },
    {
        "Drives", new JArray {
            "DVD",
            "SSD"
        }
    }
};
dynamic product = new JObject();
product.ProductName = "Elbow Grease";
product.Enabled = true;
product.Price = 4.90m;
product.StockCount = 9000;
product.StockValue = 44100;
product.Tags = new JArray("Real", "OnSale");
var writer = new JTokenWriter();
writer.WriteStartObject();
writer.WritePropertyName("name1");
writer.WriteValue("value1");
writer.WritePropertyName("name2");
writer.WriteStartArray();
writer.WriteValue(1);
writer.WriteValue(2);
writer.WriteEndArray();
writer.WriteEndObject();
var jV = (JValue)JToken.FromObject(any type);
var jO = (JObject)JToken.FromObject(any type);
JToken jT = JToken.Parse(jsonString);
JArray jA = JArray.Parse(jsonString);
JObject jO = JObject.Parse(jsonString);

LINQ to JSON - Example - JToken & JArray

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Net451Console
{
    class Program
    {
        static void Main(string[] args)
        {
            //{"ID":"","UserId":"049af3983c214e3ebf96ebb8ada62x10","UserName":"10","System":["0","1"],"EditFields":["ID","UserId","UserName","System"]}
            string json = "{\"ID\":\"\",\"UserId\":\"049af3983c214e3ebf96ebb8ada62x10\",\"UserName\":\"10\",\"System\":[\"0\",\"1\"],\"EditFields\":[\"ID\",\"UserId\",\"UserName\",\"System\"]}";

            JToken jToken = JToken.Parse(json);
            JArray jArray = (JArray)jToken["System"];
            string[] array = jArray.Select(e => e.ToString()).ToArray();
            string systems = string.Join(",", array);
            jToken["System"] = systems;
            string result = jToken.ToString().Replace("\r\n", "");
        }
    }
}

LINQ to JSON - 钛镨膏駿竤的封装

以下为 P1602\trunk\CFTC.Base\CFTC.Base.Framework\Common\ExtJson.cs 的完整内容:

using Newtonsoft.Json.Linq;

namespace CFTC.Base.Framework.Common
{
    public static class ExtJson
    {
        public static JToken ToJToken(this string json)
        {
            return JValue.Parse(json);
        }

        public static U Get<U>(this string json, string name)
        {
            return json.ToJToken().Get<U>(name);
        }

        public static U Get<U>(this JToken token, string name)
        {
            if(token[name] != null) {
                return token[name].Value<U>();
            }
            return default(U);
        }

        public static string ExtToString(this JToken jToken, string key, string defaultValue = "")
        {
            var result = jToken[key];
            return result != null ? result.ToString() : defaultValue;
        }
        public static int ExtToInt(this JToken jToken, string key, int defaultValue = 0)
        {
            var result = jToken[key];
            return result != null ? (int)result : defaultValue;
        }
    }
}

LINQ to JSON - Resource

  1. 使用 Newtonsoft.Json 动态解析 JSON
  2. JToken 类的使用,实现解析动态 JSON 数据、遍历、查找

官网 Samples 中的一些功能点

  1. 输出格式化 - 缩进 - JsonConvert.SerializeObject(account, Formatting.Indented)
  2. 处理枚举 - JsonConvert.SerializeObject(stringComparisons, new StringEnumConverter())
  3. Conditional Property & ShouldSerializeManager
  4. 反序列化父类与派生类 - CustomCreationConverter
  5. 将 JSON 字符串中的数据合并至对象实例中
  6. 通过 new JArray()new JObject() 构造 JSON 字符串 (with LINQ)
  7. 获取特定值 decimal price = (decimal)JObject.Parse(jsonString).SelectToken("Manufacturers[0].Products[0].Price");
  8. 转换为 .NET 类型 Type value = jValue.ToObject<Type>();

官网 Documentation 中的一些功能点

  1. Serialization Attributes

JsonSerializerSettings

public class Newtonsoft.Json.JsonSerializerSettings {} - Specifies the settings on a JsonSerializer object.

上述示例中已发现的功能有

  • ConstructorHandling: 是否调用非公有构造函数
  • ObjectCreationHandling: 是否替换集合成员中的重复项
  • DefaultValueHandling: 序列化对象时是否忽略默认值
  • MissingMemberHandling: 反序列化时遇到不存在的成员时是否抛出异常
  • NullValueHandling: 序列化时是否忽略值为默认值的属性。
  • ReferenceLoopHandling: 忽略循环引用值或抛出异常。
  • PreserveReferencesHandling: 2016-03-20 未理解。
  • DateFormatHandling: 控制 DateTime 和 DateTimeOffset 的格式 (IsoDateFormat "2012-12-21T00:00:00" 或 MicrosoftDateFormat "\/Date(1356044400000+0100)\/")。
  • DateTimeZoneHandling: 控制 DateTime 和 DateTimeOffset 的时区。
  • TypeNameHandling: 序列化时输出 "由 $ 开头的、附加的 类型信息"。
  • MetadataPropertyHandling: 2016-03-20 未理解。
  • ContractResolver: 自定义序列化时的规则。例如将成员名输出为首字母小写而非大写。
  • TraceWriter: 自定义序列化时的异常信息输出?
  • ErrorHandling: 自定义序列化时的异常处理逻辑、使之不抛出异常?
  • MaxDepth: 约束反序列化时的最大深度。超过该值时将抛出异常。

Example - 用 JSON 传递数据,无需定义实体类型

public ActionResult Index(string json)
{
    dynamic dyn = JsonConvert.DeserializeObject<dynamic>(json);
    int id = (int)dyn.Id;
    string name = (string)dyn.Name;
    ...
}

曾使用过的代码

var settings = new JsonSerializerSettings();
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
string json = JsonConvert.SerializeObject(prjDb, Formatting.Indented, settings);
<script>
    var currentUserInfo = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.CurrentUserInfo));
</script>
以上代码的输出形式:
<script>
    var currentUserInfo = {"UserId":"14E324DCDFFF41929C765CCF94BE9ED8","UserName":"超级管理员","LoginName":"admin","RoleNames":["EDM管理员","HEALTH管理员"],"MenuIds":null,"DeptId":"***09512E4994831B7F7D899D7FCF***","DeptName":"招标采购部","DeptCode":"128","IsSuperAdmin":"1","WeiXin":null,"QQ":null,"Mobile":"13538978***","Tel":"***01999","Email":"917911***@qq.com","AffiliatedDeptId":"***09512E4994831B7F7D899D7FCF***","AffiliatedDeptName":"招标采购部","AffiliatedDeptCode":"128","AffiliatedDeptType":"1"};
</script>
//~/CpContractInfo/GetJson/49
public ActionResult GetJson(int id)
{
    var entity = CommonBll.GetByKey<CpContractInfo>(id);
    string json = Newtonsoft.Json.JsonConvert.SerializeObject(entity);
    return Content(json, "application/json");
}
<form data-entity="@Newtonsoft.Json.JsonConvert.SerializeObject(Model)" data-sqfks='{"HYLastPayMoney": @ViewBag.HYLastPayMoney, "CWLastPayMoney": @ViewBag.CWLastPayMoney }'>
//JToken.Parse(s)

//http://localhost:8082/Services/SpecService.asmx?op=GetAllJson
[WebMethod(Description = "GetAllJson")]
public string GetAllConvert()
{
    try {
        string s = base.GetAll(String.Empty);
        string data = JToken.Parse(s)["Data"].ToString();
        return ResultToJson(data);
    }
    catch(Exception ex) {
        return ResultToJson(ex);
    }
}

循环引用/自引用/重复引用

Resource

  1. Newtonsoft.Json 的循环引用解决方案 - 循环引用: $id, $value、接口: $type、抽象类
  2. 解决 .NET MVC EntityFramework JSON 序列化循环引用问题
  3. Newtonsoft.Json 序列化 循环引用 问题 - JsonIgnoreAttribute
  4. 解决方案 - 可能是对的
  5. MVC 之 Json 序列化循环引用

通过 JsonSerializerSettings 解决问题

已发现多种方案

以下方案 详见 TL 单元测试。

//测试可行:
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
//测试可行:
//此方案 在序列化结果中增加一系列 $id, $ref 键值对 来表示 循环引用。
settings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
//测试可行:
//此方案 在序列化结果中增加一系列 $id, $ref 键值对 来表示 循环引用。
settings.PreserveReferencesHandling = PreserveReferencesHandling.All;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
//网摘,测试时抛出异常:
settings.MissingMemberHandling = MissingMemberHandling.Ignore;

上述方案的公共代码

var settings = new JsonSerializerSettings();
//上述各种方案的代码的位置
string json = JsonConvert.SerializeObject(data, Formatting.Indented, settings);

通过 JsonIgnoreAttribute 解决问题

//网摘,未测试:
[JsonIgnore]
public virtual ICollection<score> scores { get; set; }

通过 关闭 导航属性 解决问题

有网友直接关闭 导航属性/延迟加载,简单粗暴。该方法通常用于 Entity Framework 数据库优先。

关闭 导航属性/延迟加载 的方法已发现以下几种:

  • db.Configuration.ProxyCreationEnabled = false;
  • db.Configuration.LazyLoadingEnabled = false;
  • 移除 导航属性 定义中的 virtual 关键字。

示例代码:

public List<OperationMan> GetList()
{
    db.Configuration.ProxyCreationEnabled = false;
    return db.OperationMan.ToList();
}

以上代码的作用详见 ProxyCreationEnabled 和 LazyLoadingEnabled 的关系

循环引用/自引用/重复引用 - 参考 FastJson 的方案

https://github.com/alibaba/fastjson - A fast JSON parser/generator for Java. FastJson 是 阿里巴巴 的开源 JSON 解析库。

如果检测到 重复/循环引用,FastJson 默认会用 "引用标识" 代替同一对象,而非继续循环解析导致 StackOverflowError。

引用标识:
"$ref":".." 上一级。
"$ref":"@" 当前对象,也就是自引用。
"$ref":"$" 根对象。
"$ref":"$.children.0" 基于路径的引用,相当于 root.getChildren().get(0)

-- 解决 FastJson 内存对象重复/循环引用 JSON 错误

Resource

  1. Newtonsoft.Json 高级用法
  2. Newtonsoft.Json 序列化和反序列化 时间格式
  3. Newtonsoft.Json 中 JSON 数据中的 null 如何转换成 ""
  4. ASP.NET Core 中 JSON 序列化处理整理 - 一些配置
  5. C# 解析JSON方法总结
  6. Newtonsoft.Json 序列化数据,移除某个属性,返回自定义数据
  7. Newtonsoft.Json 用法
  8. Json.Net 系列教程 - by usharei - "日期处理" 在 "第三篇第五节"
  9. 超高性能的 JSON 序列化之 MVC 中使用 JSON.NET - 用 JsonIgnore 特性使得序列化时忽略导航属性
  10. StackOverflow - Newest 'json.net' Questions
  11. Newtonsoft.Json.dll 的使用
  12. 采访: James Newton-King 谈 Json.NET 4.5
  13. C# 对 XML、JSON 等格式的解析
  14. JSON 序列化之 .NET 开源类库 Newtonsoft.Json 的研究
  15. Newtonsoft.Json 中的时间格式详解
  16. Newtonsoft.Json 高级用法
  17. Newtonsoft.Json 高级用法 - 再谈
  18. Newtonsoft.Json (Json.Net) 学习笔记
  19. Newtonsoft.Json 的序列化与反序列化

Resource - 用 Newtonsoft.Json 自定义 JsonResult

  1. 用 Newtonsoft.Json 改造 MVC 默认的 JsonResult - JavaScriptSerializer 的 3 个弊端
  2. C# 学习笔记 - C# 中 Json.Net (newtonjs) 的使用
  3. MVC 使用 Newtonsoft.Json 进行序列化 JSON 数据

Resource - 动态解析

  1. 使用 Newtonsoft.Json 动态解析
  2. MVC 使用 Newtonsoft 无需实体类,实现 JSON 数据返回给前端页面使用

Resource - 用 Newtonsoft.Json 自定义 模型绑定

  1. 在 MVC 中使用 Newtonsoft.Json 序列化和反序列化 JSON 对象

Resource - Contrast

  1. JavaScriptSerializer versus Newtonsoft.Json
  2. JSON 轉換效能評比 - Json.NET,就決定是你了
  3. 几个常用 JSON 组件的性能测试