ASP.NET Core 3.1系列(29)——System.Text.Json实现JSON的序列化和反序列化

32 篇文章 39 订阅

1、前言

Web开发中,JSON数据可以说是无处不在。由于具有轻量、易读等优点,JSON已经成为当前主流的数据传输格式。在ASP.NET Core 3.0之前,大多数项目都会使用Newtonsoft.Json组件来实现JSON的序列化和反序列化操作,而从ASP.NET Core 3.1开始,微软提供的System.Text.Json已经相当出色,其效率相比前者可以说是有过之而无不及,下面就来介绍一下它的使用方法。

2、引入System.Text.Json

新建一个Web API项目,使用NuGet引入如下组件:

System.Text.Json

在这里插入图片描述
新建一个实体类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 = "男", BirthOfDate = new DateTime(2000, 1, 1) },
                new Person { Id = 2, PersonName = "李四", PersonGender = "女", BirthOfDate = new DateTime(2000, 2, 2) },
                new Person { Id = 3, PersonName = "王五", PersonGender = "男", BirthOfDate = new DateTime(2000, 3, 3) }
            };
            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"}]

上面的代码实现了一个简单的JSON序列化操作,但里面的问题也有很多,比如中文乱码、时间格式等等,下面就来说一说如何在System.Text.Json中去设置它们。

3、序列化操作

3.1、JSON数据编码

上面的运行结果显示中文乱码,我们可以使用JsonSerializerOptions中的Encoder来指定编码格式,代码如下:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;

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 = new DateTime(2000, 1, 1) },
                new Person { Id = 2, PersonName = "李四", PersonGender = "女", BirthOfDate = new DateTime(2000, 2, 2) },
                new Person { Id = 3, PersonName = "王五", PersonGender = "男", BirthOfDate = new DateTime(2000, 3, 3) }
            };
            return new JsonResult(list, new JsonSerializerOptions
            {
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            });
        }
    }
}

运行结果如下所示,可以发现中文编码正确。

[{"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文本是未经格式化的,如果你希望JSON看起来清楚一些,可以设置WriteIndented属性值,代码如下:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;

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 = new DateTime(2000, 1, 1) },
                new Person { Id = 2, PersonName = "李四", PersonGender = "女", BirthOfDate = new DateTime(2000, 2, 2) },
                new Person { Id = 3, PersonName = "王五", PersonGender = "男", BirthOfDate = new DateTime(2000, 3, 3) }
            };
            return new JsonResult(list, new JsonSerializerOptions
            {
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
                WriteIndented = true
            });
        }
    }
}

运行结果如下所示,可以发现JSON文本已经被格式化了。

[
  {
    "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字段命名格式

上面的输出结果遵循的是首字母大写的帕斯卡命名格式,如果希望输出结果采用驼峰式进行命名,则可以对PropertyNamingPolicy进行设置,代码如下:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;

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 = new DateTime(2000, 1, 1) },
                new Person { Id = 2, PersonName = "李四", PersonGender = "女", BirthOfDate = new DateTime(2000, 2, 2) },
                new Person { Id = 3, PersonName = "王五", PersonGender = "男", BirthOfDate = new DateTime(2000, 3, 3) }
            };
            return new JsonResult(list, new JsonSerializerOptions
            {
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
                WriteIndented = true,
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            });
        }
    }
}

运行结果如下所示,可以发现JSON文本采用的是驼峰式命名。

[
  {
    "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,则结果中也会显示为null。如果希望忽略null值,则可以对DefaultIgnoreCondition进行设置,代码如下:

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;

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, new JsonSerializerOptions
            {
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
                WriteIndented = true,
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
            });
        }
    }
}

运行结果如下所示,可以发现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}"; }
        }
    }
}

我们可以对JsonSerializerOptions中的IgnoreReadOnlyProperties字段进行设置,从而忽略只读字段,代码如下:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;

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 = new DateTime(2000, 1, 1) },
                new Person { Id = 2, PersonName = "李四", PersonGender = "女", BirthOfDate = new DateTime(2000, 2, 2) },
                new Person { Id = 3, PersonName = "王五", PersonGender = "男", BirthOfDate = new DateTime(2000, 3, 3) }
            };
            return new JsonResult(list, new JsonSerializerOptions
            {
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
                WriteIndented = true,
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
                IgnoreReadOnlyProperties = true
            });
        }
    }
}

运行结果如下所示,可以发现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中的时间格式

在上面的代码中,时间字段BirthOfDate的序列化结果有一些问题,如何把它序列化成我们熟悉的时间格式呢?首先定义一个类DateTimeJsonConverter,该类继承JsonConverter<DateTime>,代码如下:

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace App
{
    public class DateTimeJsonConverter : JsonConverter<DateTime>
    {
        public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType == JsonTokenType.String)
            {
                if (DateTime.TryParse(reader.GetString(), out DateTime dateTime))
                {
                    return dateTime;
                }
            }
            return reader.GetDateTime();
        }

        public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString("yyyy年MM月dd日 HH时mm分ss秒"));
        }
    }
}

然后在JsonSerializerOptions中的Converters集合中加入它即可,代码如下:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;

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 = new DateTime(2000, 1, 1, 0, 0, 0) },
                new Person { Id = 2, PersonName = "李四", PersonGender = "女", BirthOfDate = new DateTime(2000, 2, 2) },
                new Person { Id = 3, PersonName = "王五", PersonGender = "男", BirthOfDate = new DateTime(2000, 3, 3) }
            };

            JsonSerializerOptions options = new JsonSerializerOptions
            {
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
                WriteIndented = true,
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
            };
            options.Converters.Add(new DateTimeJsonConverter());

            return new JsonResult(list, options);
        }
    }
}

运行结果如下所示,可以发现BirthOfDate字段的值已经被格式化。

[
  {
    "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秒"
  }
]

4、反序列化操作

4.1、常规操作

JSON的反序列化操作比较简单,只需要调用Deserialize即可。代码如下:

using Microsoft.AspNetCore.Mvc;
using System.Text.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-01T00:00:00\"}";
            Person person = JsonSerializer.Deserialize<Person>(json);
            return $"姓名:{person.PersonName}\n性别:{person.PersonGender}\n出生日期:{person.BirthOfDate}";
        }
    }
}

运行结果如下所示:

姓名:张三
性别:男
出生日期:2000/1/1 0:00:00

4.2、特殊情况的处理

在进行反序列化操作时,有一种情况需要特别注意,那就是属性值末尾存在逗号的情况。在JavaScript中,下面的代码是允许的,即:在BirthOfDate的属性值后面允许添加一个逗号:

{
  "Id": 1,
  "PersonName": "张三",
  "PersonGender": "男",
  "BirthOfDate": "2000-01-01T00:00:00",
}

但这种情况会导致反序列化报错,代码如下:

using Microsoft.AspNetCore.Mvc;
using System.Text.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-01T00:00:00\",}";
            Person person = JsonSerializer.Deserialize<Person>(json);
            return $"姓名:{person.PersonName}\n性别:{person.PersonGender}\n出生日期:{person.BirthOfDate}";
        }
    }
}

运行结果如下图所示:

在这里插入图片描述
如果要允许这种末尾添加逗号的情况,需要设置JsonSerializerOptionsAllowTrailingCommas属性,代码如下:

using Microsoft.AspNetCore.Mvc;
using System.Text.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-01T00:00:00\",}";
            Person person = JsonSerializer.Deserialize<Person>(json, new JsonSerializerOptions
            {
                AllowTrailingCommas = true
            });
            return $"姓名:{person.PersonName}\n性别:{person.PersonGender}\n出生日期:{person.BirthOfDate}";
        }
    }
}

运行结果如下所示:

姓名:张三
性别:男
出生日期:2000/1/1 0:00:00

5、全局配置JSON

上面的代码是在单个方法中设置JSON操作属性,如果当前存在很多方法,则必然会导致代码臃肿。我们可以在全局对JSON进行配置,代码如下:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.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().AddJsonOptions(options =>
            {
                // 设置编码格式
                options.JsonSerializerOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;

                // 是否格式化文本
                options.JsonSerializerOptions.WriteIndented = true;

                // 添加时间格式化转换器
                options.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter());

                // 字段采用驼峰式命名
                options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;

                // 忽略null值
                options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;

                // 忽略只读字段
                options.JsonSerializerOptions.IgnoreReadOnlyProperties = true;

                // 允许属性值末尾存在逗号
                options.JsonSerializerOptions.AllowTrailingCommas = true;

                // 处理循环引用类型
                options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
            });
        }

        // 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();
            });
        }
    }
}

在全局进行配置后,Controller中的方法就不需要单独配置了,代码如下:

using Microsoft.AspNetCore.Mvc;
using System;
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 = new DateTime(2000, 1, 1, 0, 0, 0) },
                new Person { Id = 2, PersonName = "李四", PersonGender = "女", BirthOfDate = new DateTime(2000, 2, 2) },
                new Person { Id = 3, PersonName = "王五", PersonGender = "男", BirthOfDate = new DateTime(2000, 3, 3) }
            };
            return new JsonResult(list);
        }
    }
}

运行结果如下所示:

[
  {
    "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秒"
  }
]

6、结语

本文简单介绍了ASP.NET Core中关于JSON序列化和反序列化操作,主要通过System.Text.Json来实现。如果你觉得微软提供的JSON序列化工具不好用,那也可以使用Newtonsoft.Json,我也会在下一篇博客中介绍关于Newtonsoft.Json的使用方法。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ASP.NET Core 3.1是一个跨平台、高性能的开源框架,它可以帮助我们快速地构建Web应用程序。ASP.NET Core 3.1中文教程可以为初学者提供一个快速上手的指南,帮助他们了解和掌握该框架的各种功能。 在学习ASP.NET Core 3.1教程之前,我们需要了解一些基本的编程概念和技能, 包括C#语言的基础知识、MVC(Model View Controller)等常见的编程模式、以及前端技术如HTML、CSS和JavaScript等。此外,我们还需要对.NET Core框架有一定的了解,如.NET Core的概念、架构和基础组件等。 学习ASP.NET Core 3.1的教程需要深入理解其设计方案和特点,例如跨平台、高性能、依赖注入、实时通信等。此外,我们还需要熟悉其主要组件,如ASP.NET Core的中间件、MVC框架、Entity Framework Core等。 在学习ASP.NET Core 3.1的教程时,我们需要通过实践才能更好地理解其所涉及的技术和概念。因此,我们需要通过编写各种实际的Web应用程序和示例,来实践和掌握所学的技巧和知识。 总之,学习ASP.NET Core 3.1的中文教程需要较深的前置知识储备和实操经验,而且需要坚持不懈地学习和练习以提高自己的技能水平。 ### 回答2: ASP.NET Core 3.1是目前为止最新的ASP.NET Core版本,它是一个跨平台的Web应用程序开发框架。对于想要学习ASP.NET Core 3.1的开发者来说,中文教程是非常重要的。 现在,有很多中文教程可以帮助开发者快速入门ASP.NET Core 3.1。这些教程通常包括以下内容: 1. ASP.NET Core 3.1的基础知识:网页处理、路由、控制器等; 2. ASP.NET Core 3.1中的模型、视图和控制器; 3. 动作过滤器和特性; 4. 实体框架和数据库相关操作; 5. API设计和测试等。 这些教程通常包含实例和练习,能够帮助开发者深入理解ASP.NET Core 3.1的开发原理。另外,一些知名的在线教育平台,如网易云课堂等,也提供了ASP.NET Core 3.1的中文课程,有兴趣的开发者可以去尝试。 总的来说,学习ASP.NET Core 3.1需要投入时间和精力,但是中文教程能够让初学者更加轻松地掌握ASP.NET Core 3.1的开发技能,更好地进行ASP.NET Core 3.1的开发工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值