ASP.NET Core 3.1系列(30)——Newtonsoft.Json实现JSON的序列化和反序列化
1、前言
在早期版本的ASP.NET Core
项目中,Newtonsoft.Json
的使用率非常高。虽然微软当前主推System.Text.Json
来处理JSON
的序列化和反序列化,但Newtonsoft.Json
在这方面做的也是相当不错,下面就来介绍一下它的用法。
2、引入Newtonsoft.Json
新建一个Web API
项目,使用NuGet
引入如下组件:
Microsoft.AspNetCore.Mvc.NewtonsoftJson
新建一个实体类Person
,代码如下:
using System;
namespace App
{
public class Person
{
public int Id { get; set; }
public string PersonName { get; set; }
public string PersonGender { get; set; }
public DateTime? BirthOfDate { get; set; }
}
}
新建一个控制器PersonController
,添加一个Get
方法,代码如下:
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class PersonController : ControllerBase
{
[HttpGet]
public JsonResult Get()
{
List<Person> list = new List<Person>
{
new Person { Id = 1, PersonName = "张三", PersonGender = "男", PersonAge = 30 },
new Person { Id = 2, PersonName = "李四", PersonGender = "女", PersonAge = 31 },
new Person { Id = 3, PersonName = "王五", PersonGender = "男", PersonAge = 32 }
};
return new JsonResult(list);
}
}
}
运行结果如下所示:
[{"id":1,"personName":"\u5F20\u4E09","personGender":"\u7537","birthOfDate":"2000-01-01T00:00:00"},{"id":1,"personName":"\u674E\u56DB","personGender":"\u5973","birthOfDate":"2000-02-02T00:00:00"},{"id":1,"personName":"\u738B\u4E94","personGender":"\u7537","birthOfDate":"2000-03-03T00:00:00"}]
与之前一样,这里存在中文乱码、时间格式等等,下面就来说一说如何在Newtonsoft.Json
中去设置它们。
3、序列化操作
3.1、JSON数据编码
这里与System.Text.Json
需要指定编码格式不同,我们只需要指定Newtonsoft.Json
为全局序列化的工具即可,代码如下:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace App
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson(options =>
{
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
运行结果如下所示,可以发现中文编码正确。
[{"id":1,"personName":"张三","personGender":"男","birthOfDate":"2000-01-01T00:00:00"},{"id":2,"personName":"李四","personGender":"女","birthOfDate":"2000-02-02T00:00:00"},{"id":3,"personName":"王五","personGender":"男","birthOfDate":"2000-03-03T00:00:00"}]
3.2、JSON文本格式化
如果希望将输出的JSON
文本格式化,可以对Formatting
进行设置,代码如下:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
namespace App
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson(options =>
{
// 格式化JSON文本
options.SerializerSettings.Formatting = Formatting.Indented;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
运行结果如下所示:
[
{
"id": 1,
"personName": "张三",
"personGender": "男",
"birthOfDate": "2000-01-01T00:00:00"
},
{
"id": 2,
"personName": "李四",
"personGender": "女",
"birthOfDate": "2000-02-02T00:00:00"
},
{
"id": 3,
"personName": "王五",
"personGender": "男",
"birthOfDate": "2000-03-03T00:00:00"
}
]
3.3、JSON字段命名格式
如果你希望采用驼峰式命名,可以设置ContractResolver
为CamelCasePropertyNamesContractResolver
,代码如下:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace App
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson(options =>
{
// 格式化JSON文本
options.SerializerSettings.Formatting = Formatting.Indented;
// 驼峰式命名
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
运行结果如下所示:
[
{
"id": 1,
"personName": "张三",
"personGender": "男",
"birthOfDate": "2000-01-01T00:00:00"
},
{
"id": 2,
"personName": "李四",
"personGender": "女",
"birthOfDate": "2000-02-02T00:00:00"
},
{
"id": 3,
"personName": "王五",
"personGender": "男",
"birthOfDate": "2000-03-03T00:00:00"
}
]
如果你希望采用帕斯卡命名,可以设置ContractResolver
为DefaultContractResolver
,代码如下:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace App
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson(options =>
{
// 格式化JSON文本
options.SerializerSettings.Formatting = Formatting.Indented;
// 帕斯卡命名
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
运行结果如下所示:
[
{
"Id": 1,
"PersonName": "张三",
"PersonGender": "男",
"BirthOfDate": "2000-01-01T00:00:00"
},
{
"Id": 2,
"PersonName": "李四",
"PersonGender": "女",
"BirthOfDate": "2000-02-02T00:00:00"
},
{
"Id": 3,
"PersonName": "王五",
"PersonGender": "男",
"BirthOfDate": "2000-03-03T00:00:00"
}
]
3.4、忽略JSON中的null值
如果希望忽略null
值,可设置NullValueHandling
属性,代码如下:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace App
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson(options =>
{
// 格式化JSON文本
options.SerializerSettings.Formatting = Formatting.Indented;
// 驼峰式命名
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
// 忽略null值
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
修改一下PersonController
,将BirthOfDate
设置为null
,代码如下:
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class PersonController : ControllerBase
{
[HttpGet]
public JsonResult Get()
{
List<Person> list = new List<Person>
{
new Person { Id = 1, PersonName = "张三", PersonGender = "男", BirthOfDate = null },
new Person { Id = 2, PersonName = "李四", PersonGender = "女", BirthOfDate = null },
new Person { Id = 3, PersonName = "王五", PersonGender = "男", BirthOfDate = null }
};
return new JsonResult(list);
}
}
}
运行结果如下所示,可以发现BirthOfDate
字段并未被序列化。
[
{
"id": 1,
"personName": "张三",
"personGender": "男"
},
{
"id": 2,
"personName": "李四",
"personGender": "女"
},
{
"id": 3,
"personName": "王五",
"personGender": "男"
}
]
3.5.、JSON忽略只读字段
在Person
中添加一个只读字段Info
,代码如下:
using System;
namespace App
{
public class Person
{
public int Id { get; set; }
public string PersonName { get; set; }
public string PersonGender { get; set; }
public DateTime? BirthOfDate { get; set; }
public string Info
{
get { return $"姓名:{PersonName},性别:{PersonGender},出生日期:{BirthOfDate}"; }
}
}
}
关于忽略只读字段,System.Text.Json
已经支持设置该属性,但Newtonsoft.Json
并没有提供对应属性来支持它,因此我们需要自己动手实现。新建一个类IgnoreReadOnlyPropertiesResolver
,代码如下:
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
namespace App
{
public class IgnoreReadOnlyPropertiesResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
return props.Where(p => p.Readable && p.Writable).ToList();
}
}
}
然后将ContractResolver
属性的值替换为IgnoreReadOnlyPropertiesResolver
,代码如下:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace App
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson(options =>
{
// 格式化JSON文本
options.SerializerSettings.Formatting = Formatting.Indented;
// 忽略只读字段
options.SerializerSettings.ContractResolver = new IgnoreReadOnlyPropertiesResolver();
// 忽略null值
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
运行结果如下所示,可以发现Info
字段并未被序列化。
[
{
"Id": 1,
"PersonName": "张三",
"PersonGender": "男",
"BirthOfDate": "2000-01-01T00:00:00"
},
{
"Id": 2,
"PersonName": "李四",
"PersonGender": "女",
"BirthOfDate": "2000-02-02T00:00:00"
},
{
"Id": 3,
"PersonName": "王五",
"PersonGender": "男",
"BirthOfDate": "2000-03-03T00:00:00"
}
]
3.6、JSON中的时间格式
在System.Text.Json
中,我们需要通过自定义类来实现时间字段的格式化, 而Newtonsoft.Json
中的时间格式化则非常简单,我们只需要对DateFormatString
进行设置即可,代码如下:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace App
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson(options =>
{
// 格式化JSON文本
options.SerializerSettings.Formatting = Formatting.Indented;
// 忽略只读字段
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
// 忽略null值
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
// 设置时间格式
options.SerializerSettings.DateFormatString = "yyyy年MM月dd日 HH时mm分ss秒";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
运行结果如下所示,可以发现时间字段已经被格式化。
[
{
"id": 1,
"personName": "张三",
"personGender": "男",
"birthOfDate": "2000年01月01日 00时00分00秒"
},
{
"id": 2,
"personName": "李四",
"personGender": "女",
"birthOfDate": "2000年02月02日 00时00分00秒"
},
{
"id": 3,
"personName": "王五",
"personGender": "男",
"birthOfDate": "2000年03月03日 00时00分00秒"
}
]
3.7、忽略循环引用
如果涉及到一对多关联表的查询时,JSON
序列化会产生循环引用问题,解决方法就是对ReferenceLoopHandling
进行设置,代码如下:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace App
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson(options =>
{
// 格式化JSON文本
options.SerializerSettings.Formatting = Formatting.Indented;
// 忽略只读字段
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
// 忽略null值
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
// 设置时间格式
options.SerializerSettings.DateFormatString = "yyyy年MM月dd日 HH时mm分ss秒";
// 忽略循环引用
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
4、反序列化操作
Newtonsoft.Json
中的反序列化操作很简单,只需要调用JsonConvert.DeserializeObject
即可,代码如下:
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class PersonController : ControllerBase
{
[HttpGet]
public ActionResult<string> Get()
{
string json = "{\"Id\":1,\"PersonName\":\"张三\",\"PersonGender\":\"男\",\"BirthOfDate\":\"2000-01-01 00:00:00\"}";
Person person = JsonConvert.DeserializeObject<Person>(json);
return $"姓名:{person.PersonName}\n性别:{person.PersonGender}\n出生日期:{person.BirthOfDate}";
}
}
}
运行结果如下所示:
姓名:张三
性别:男
出生日期:2000/1/1 0:00:00
5、结语
本文主要介绍了Newtonsoft.Json
的使用方法。其实System.Text.Json
和Newtonsoft.Json
的使用方法都很简便,具体在项目中使用哪个序列化工具可根据情况自行决定。