.NET Core 3.0 System.Text.Json 和 Newtonsoft.Json 行为不一致问题及解决办法

行为不一致

.NET Core 3.0 新出了个内置的 JSON 库, 全名叫做尼古拉斯 System.Text.Json - 性能更高占用内存更少这都不是事...

对我来说, 很多或大或小的项目能少个第三方依赖项, 还能规避多个依赖项的依赖 Newtonsoft.Json 版本不一致的问题, 是件极美的事情.

但是, 结果总不是不如预期那么简单和美好, 简单测试了下, 有一些跟 Newtonsoft.Json 行为不一致的地方, 代码如下:

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTestProject3
{
    [TestClass]
    public class TestJsonDiff
    {
        [TestMethod]
        [Description(description: "测试数字序列化")]
        public void TestNumber()
        {
            object jsonObject = new { number = 123.456 };
            string aJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(value: jsonObject);
            string bJsonString = System.Text.Json.JsonSerializer.Serialize(value: jsonObject);

            Assert.AreEqual(expected: aJsonString, actual: bJsonString, message: "测试数字序列化失败");
        }

        [TestMethod]
        [Description(description: "测试英文序列化")]
        public void TestEnglish()
        {
            object jsonObject = new { english = "bla bla" };
            string aJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(value: jsonObject);
            string bJsonString = System.Text.Json.JsonSerializer.Serialize(value: jsonObject);

            Assert.AreEqual(expected: aJsonString, actual: bJsonString, message: "测试英文序列化失败");
        }

        [TestMethod]
        [Description(description: "测试中文序列化")]
        public void TestChinese()
        {
            object jsonObject = new { chinese = "灰长标准的布咚发" };
            string aJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(value: jsonObject);
            string bJsonString = System.Text.Json.JsonSerializer.Serialize(value: jsonObject);

            Assert.AreEqual(expected: aJsonString, actual: bJsonString, message: "测试中文序列化失败");
        }

        [TestMethod]
        [Description(description: "测试英文符号")]
        public void TestEnglishSymbol()
        {
            object jsonObject = new { symbol = @"~`!@#$%^&*()_-+={}[]:;'<>,.?/ " };
            string aJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(value: jsonObject);
            string bJsonString = System.Text.Json.JsonSerializer.Serialize(value: jsonObject);

            Assert.AreEqual(expected: aJsonString, actual: bJsonString, message: "测试英文符号失败");
        }

        [TestMethod]
        [Description(description: "测试中文符号")]
        public void TestChineseSymbol()
        {
            object jsonObject = new { chinese_symbol = @"~·@#¥%……&*()—-+={}【】;:“”‘’《》,。?、" };
            string aJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(value: jsonObject);
            string bJsonString = System.Text.Json.JsonSerializer.Serialize(value: jsonObject);

            Assert.AreEqual(expected: aJsonString, actual: bJsonString, message: "测试中文符号失败");
        }

    }
}

先来看看总体的测试结果:

这是 VS 显示的结果

.NET Core 3.0 System.Text.Json 和 Newtonsoft.Json 行为不一致问题及解决办法_第1张图片

这是执行 dotnet test 命令行显示的结果

.NET Core 3.0 System.Text.Json 和 Newtonsoft.Json 行为不一致问题及解决办法_第2张图片

这个时候需要配个图

.NET Core 3.0 System.Text.Json 和 Newtonsoft.Json 行为不一致问题及解决办法_第3张图片

那么问题来了, 国庆去哪玩比较好呢, 我是谁? 这是哪? 发生了什么?

解决办法

解决中文会被 Unicode 编码的问题

这个问题是在博客园里找到的一种答案: .NET Core 3.0 中使用 System.Text.Json 序列化中文时的编码问题

[TestMethod]
[Description(description: "测试中文序列化")]
public void TestChinese()
{
    object jsonObject = new { chinese = "灰长标准的布咚发" };
    string aJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(value: jsonObject);
    string bJsonString = System.Text.Json.JsonSerializer.Serialize(
        value: jsonObject,
        options: new System.Text.Json.JsonSerializerOptions
        {
            Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(allowedRanges: UnicodeRanges.All)
        });

    Assert.AreEqual(expected: aJsonString, actual: bJsonString, message: "测试中文序列化失败");
}

关键在于序列化配置加了一句

new System.Text.Json.JsonSerializerOptions
{
    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(allowedRanges: UnicodeRanges.All)
}

但是一些符号被转义的问题还是不管用, 寻思了一上午暂时没找到答案...

至于什么时候修复此类问题,

.NET Core 3.0 System.Text.Json 和 Newtonsoft.Json 行为不一致问题及解决办法_第4张图片

我去源码 corefx 溜个一圈, 暂时的发现是归到了 .NET Core 3.1 和 5.0 的开发时间线里...后面回来发现这不应该啊

但是...难道就这样了?

怀着受伤的核桃心, 中午又吃了3只大闸蟹...

诡异的是新建 ASP.NET Core API (.NET Core 3.0) 输出的 JSON 中文和转义字符都是正常, 如图:

.NET Core 3.0 System.Text.Json 和 Newtonsoft.Json 行为不一致问题及解决办法_第5张图片

说明一定是我们打开的方式不对...回娘家找源码, 寻寻匿匿最后发现这么一句

// If the user hasn't explicitly configured the encoder, use the less strict encoder that does not encode all non-ASCII characters.
jsonSerializerOptions = jsonSerializerOptions.Copy(JavaScriptEncoder.UnsafeRelaxedJsonEscaping);

less strict ? 那对照的意思是 Newtonsoft.Json 一直使用的就是非严格模式咯, 而我们习惯使用的也是这种模式.

那么改下, 还报错的单元测试都加上配置 JavaScriptEncoder.UnsafeRelaxedJsonEscaping, 果然测试结果顺眼多了. 连上面的 UnicodeRanges.All 都不需要配置了.

string bJsonString = System.Text.Json.JsonSerializer.Serialize(
	value: jsonObject,
	options: new System.Text.Json.JsonSerializerOptions
	{
		Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
	});

.NET Core 3.0 System.Text.Json 和 Newtonsoft.Json 行为不一致问题及解决办法_第6张图片

又整明白一个问题, 开森...

你可能感兴趣的:(.NET Core 3.0 System.Text.Json 和 Newtonsoft.Json 行为不一致问题及解决办法)