拓冰建站拓冰建站
首页 / 资讯中心 / 正文

System.Text.Json 对比 Newtonsoft:缺失功能与完整补救方案

.NET 生态里JSON 序列化是一个绕不开的话题。早期我们几乎都用 Newtonsoft.Json它功能丰富、API 友好几乎所有 .NET 项目里都能看到JsonConvert.SerializeObject的身影。后来微软推出了原生 System.Text.Json性能和内存占用更优并且成为 ASP.NET Core 默认的 JSON 序列化组件。但很多开发者在迁移时发现System.Text.Json 虽然够快却在某些功能上不如 Newtonsoft 顺手网上相关的对比资料也比较零散。本文会把 System.Text.Json 相对 Newtonsoft 缺失的常用功能梳理清楚并给出对应的补救方案和完整代码示例新人能做技术选型参考老手也能直接在项目中复用。1. 背景为什么 System.Text.Json 和 Newtonsoft 会有差异1.1 Newtonsoft 的历史地位Newtonsoft.Json 从 .NET 时代早期就开始流行一度是 .NET 阵营里 JSON 处理的“事实标准”。它的设计理念是“功能尽量完整”从简单的对象序列化到复杂的自定义转换器、多态处理、动态对象操作几乎都能找到对应 API。哪怕到现在很多老项目的底层还是 Newtonsoft甚至某些第三方 SDK 也不可避免地依赖它。Newtonsoft 的优势主要有三个API 语义直观JObject、JArray这类 LINQ to JSON 操作非常灵活。配置项丰富比如日期格式、null 值处理、循环引用处理、枚举转换等都有现成配置。支持大量 .NET Framework 时代的历史项目社区资料多踩坑经验也多。1.2 System.Text.Json 的诞生与优势System.Text.Json 是微软从 .NET Core 3.0 开始逐步引入的高性能 JSON 库后续在 .NET 5、.NET 6、.NET 7、.NET 8 中不断增强。它从一开始就把“高性能”和“低内存分配”放在首位在很多性能敏感场景中速度明显优于 Newtonsoft。另外System.Text.Json 还提供了源生成Source Generation模式可以在编译阶段生成专门的序列化代码避免运行时反射这在 AOT 发布和启动速度优化场景中很有价值。1.3 为什么会有“缺失功能”的感知严格来说System.Text.Json 并不是单纯地“少功能”而是设计理念不同。Newtonsoft 倾向于在运行时通过反射和动态配置解决问题System.Text.Json 则更强调显式配置、编译期安全和性能上限。于是某些 Newtonsoft 中“开箱即用”的能力在 System.Text.Json 中可能需要用转换器Converter、特性Attribute或额外配置来实现。本文把这些差异统一称为“缺失功能”更多是指“没有直接等价配置”的功能。2. 环境准备与版本说明本文示例以 .NET 8 为主但大部分代码适用于 .NET 6 以上的版本。如果你的项目还在使用 .NET Core 3.1 或 .NET 5部分 API 可能不存在需要根据实际版本调整。操作系统Windows 10/11、macOS、Linux 均可SDK.NET 6 或 .NET 8IDEVisual Studio 2022 或 Rider 或 VS Code示例类型控制台项目 ASP.NET Core Web API待对比组件Newtonsoft.Json推荐 13.0.x 版本如果你还没有项目可以先用命令创建控制台工程dotnet new console -n JsonComparisonDemo cd JsonComparisonDemo为了让同一个项目里同时引用 System.Text.Json 和 Newtonsoft.Json可以在项目文件里添加 Newtonsoft 包dotnet add package Newtonsoft.Json注意System.Text.Json 在 .NET Core 3.0 中已经内置无需额外引入除非你的目标是 .NET Framework 或旧版本。3. System.Text.Json 与 Newtonsoft 的核心差异盘点这一节先做整体对比后续章节再演示具体补救方式。下表是高频使用场景中两者行为的对比功能场景Newtonsoft.JsonSystem.Text.Json默认属性大小写默认区分大小写可通过 settings 开启忽略默认区分大小写需配置PropertyNameCaseInsensitivenull 属性处理默认输出可配置NullValueHandling.Ignore默认输出可配置JsonIgnoreCondition.WhenWritingNull默认值处理可配置DefaultValueHandling.Ignore可配置JsonIgnoreCondition.WhenWritingDefaultDateTime 自定义格式通过DateFormatString直接配置无直接配置需要自定义 Converter循环引用默认报错可配置ReferenceLoopHandling.Ignore默认直接抛异常需配置ReferenceHandler.IgnoreCycles多态序列化通过TypeNameHandling或自定义转换器通过[JsonDerivedType]和JsonPolymorphic特性条件序列化ShouldSerializeXxx支持较方便无直接等价需自定义转换器自定义属性名策略ContractResolver可自由扩展通过PropertyNamingPolicy和JsonNamingPolicy实现常见策略枚举字符串转换StringEnumConverterJsonStringEnumConverter动态 JSON 操作JObject/JArray非常灵活使用JsonNode/JsonObject/JsonArray忽略特定属性[JsonIgnore][JsonIgnore]新增加属性处理MissingMemberHandling可控制有UnmappedMemberHandling.NET 8从表格可见System.Text.Json 并不是完全不具备这些能力而是入口不同。下面我们按功能维度拆开讲。4. 常用缺失功能与补救方案4.1 自定义 DateTime 日期时间格式4.1.1 Newtonsoft 的简单方案Newtonsoft 中要把 DateTime 序列化为yyyy-MM-dd HH:mm:ss格式只需设置DateFormatStringvar settings new JsonSerializerSettings { DateFormatString yyyy-MM-dd HH:mm:ss }; var json JsonConvert.SerializeObject(new { CreateTime DateTime.Now }, settings); Console.WriteLine(json);输出{CreateTime:2025-01-15 14:30:00}4.1.2 System.Text.Json 的补救方案System.Text.Json 默认只支持 ISO 8601 格式DateTime序列化结果形如2025-01-15T14:30:00。如果前端喜欢用自定义格式最常见的做法是写一个自定义JsonConverterDateTime。using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; public class DateTimeConverter : JsonConverterDateTime { private readonly string _format; public DateTimeConverter(string format yyyy-MM-dd HH:mm:ss) { _format format; } public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType JsonTokenType.String) { if (DateTime.TryParseExact(reader.GetString(), _format, CultureInfo.InvariantCulture, DateTimeStyles.None, out var date)) { return date; } } // 回退到默认解析 return reader.GetDateTime(); } public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString(_format, CultureInfo.InvariantCulture)); } }使用时可以手动注册var options new JsonSerializerOptions { Converters { new DateTimeConverter(yyyy-MM-dd HH:mm:ss) } }; var json JsonSerializer.Serialize(new { CreateTime DateTime.Now }, options); Console.WriteLine(json);在 ASP.NET Core 中可以在AddJsonOptions里全局注册builder.Services.AddControllers() .AddJsonOptions(options { options.JsonSerializerOptions.Converters.Add(new DateTimeConverter(yyyy-MM-dd HH:mm:ss)); });这里需要注意如果前端反传日期也必须使用相同格式或者你的 Converter 里要做好兼容解析否则可能抛出JsonException。实际项目里更稳妥的做法是允许传入 ISO 格式和自定义格式或者前后端统一标准。4.2 属性名称大小写不敏感4.2.1 问题表现在 System.Text.Json 中反序列化时默认严格匹配属性名大小写。例如 JSON 里是UserName而 C# 属性是UserName这是没有问题的但如果 JSON 里是username默认情况下就匹配不上。4.2.2 补救方案配置PropertyNameCaseInsensitive true或者使用PropertyNamingPolicy处理驼峰命名。var options new JsonSerializerOptions { PropertyNameCaseInsensitive true, PropertyNamingPolicy JsonNamingPolicy.CamelCase }; var user JsonSerializer.DeserializeUser(json, options);在 ASP.NET Core 中默认已经把 JSON 属性名按 CamelCase 处理了但反序列化是否忽略大小写取决于配置。如果接口需要兼容多种命名风格建议开启builder.Services.AddControllers() .AddJsonOptions(options { options.JsonSerializerOptions.PropertyNameCaseInsensitive true; });需要注意的是虽然开启PropertyNameCaseInsensitive会影响性能但绝大多数业务系统感知不到差异不用过度担心。4.3 忽略 null 属性和默认值属性4.3.1 需求背景很多接口为了减少无效字段会要求序列化时跳过值为 null 的字段或者跳过值为默认值的字段比如 int 为 0bool 为 false。Newtonsoft 里直接配置var settings new JsonSerializerSettings { NullValueHandling NullValueHandling.Ignore, DefaultValueHandling DefaultValueHandling.Ignore };System.Text.Json 中需要在JsonSerializerOptions里设置DefaultIgnoreCondition。using System.Text.Json; using System.Text.Json.Serialization; var options new JsonSerializerOptions { DefaultIgnoreCondition JsonIgnoreCondition.WhenWritingNull }; var json JsonSerializer.Serialize(new { Name 张三, Remark (string?)null }, options); Console.WriteLine(json);输出中Remark字段会被忽略{Name:张三}如果还要忽略默认值var options new JsonSerializerOptions { DefaultIgnoreCondition JsonIgnoreCondition.WhenWritingDefault };这里需要明确WhenWritingDefault会同时忽略 null 和值类型的默认值比如int的0、bool的false。如果只想忽略引用类型的 null用WhenWritingNull。另一个常见需求是针对单个属性的忽略可以使用[JsonIgnore]这一点两个库的行为一致。但 System.Text.Json 还支持带条件的特性写法public class User { public string Name { get; set; } [JsonIgnore(Condition JsonIgnoreCondition.WhenWritingNull)] public string? Phone { get; set; } }这种方式对某些特定字段的忽略非常方便不需要改全局配置。4.4 循环引用处理4.4.1 问题场景当对象存在互相引用时比如订单里有用户用户里又有订单列表默认情况下序列化会陷入无限递归。Newtonsoft 默认也会抛异常但可以通过ReferenceLoopHandling.Ignore直接忽略循环引用var settings new JsonSerializerSettings { ReferenceLoopHandling ReferenceLoopHandling.Ignore };System.Text.Json 默认遇到循环引用会抛JsonException提示遇到了循环引用。从 .NET 5 开始可以通过ReferenceHandler来处理。方案一忽略循环引用var options new JsonSerializerOptions { ReferenceHandler ReferenceHandler.IgnoreCycles }; var json JsonSerializer.Serialize(order, options);方案二保留引用关系如果你需要保留对象引用结构而不是简单忽略可以使用ReferenceHandler.Preserve这样会在 JSON 中写入$id、$ref等元数据但往往不是常规接口想要的格式。大多数业务接口只需要IgnoreCycles。注意ReferenceHandler.IgnoreCycles在遇到循环时会把第二次出现的对象序列化为null而不是直接报错。这与 Newtonsoft 的ReferenceLoopHandling.Ignore行为不完全相同但通常能满足“不报错”的需求。4.5 多态序列化4.5.1 为什么需要多态当你的接口返回类型是基类但实际数据是子类时反序列化时如果不做特殊处理得到的对象将丢失子类属性。比如Animal基类下有Dog和Cat子类public class Animal { public string Name { get; set; } } public class Dog : Animal { public bool CanBark { get; set; } } public class Cat : Animal { public bool CanCatchMouse { get; set; } }如果直接序列化Animal列表子类特有属性会被丢弃反序列化时也会退化成基类。4.5.2 Newtonsoft 的做法Newtonsoft 可以在序列化时写入$type字段反序列化时根据类型信息还原子类。通常使用TypeNameHandlingvar settings new JsonSerializerSettings { TypeNameHandling TypeNameHandling.All };但这种做法有一定安全隐患如果反序列化来源不可信可能造成类型混淆攻击。所以在新系统中我不会建议直接使用TypeNameHandling.All。4.5.3 System.Text.Json 的推荐做法从 .NET 7 开始System.Text.Json 提供了更安全的基于特性的多态支持[JsonDerivedType(typeof(Dog), typeDiscriminator: dog)] [JsonDerivedType(typeof(Cat), typeDiscriminator: cat)] public class Animal { public string Name { get; set; } }序列化时会写入一个$type判别字段{ $type: dog, Name: 旺财, CanBark: true }反序列化时也需要设置JsonSerializerOptionsvar options new JsonSerializerOptions { PropertyNameCaseInsensitive true }; var json {\$type\:\dog\,\Name\:\旺财\,\CanBark\:true}; var animal JsonSerializer.DeserializeAnimal(json, options);这样得到的对象就能正确还原成Dog。这种方式比 Newtonsoft 更安全因为类型判别值由开发者显式指定不会默认携带程序集名和类型名。如果你的项目使用 .NET 6 及以下版本则只能通过自定义转换器实现多态代码会复杂一些。4.6 条件序列化替代 ShouldSerializeXxx4.6.1 Newtonsoft 的 ShouldSerialize 机制Newtonsoft 支持通过定义ShouldSerializeXxx()方法动态控制属性是否参与序列化public class Person { public string Name { get; set; } public string? Secret { get; set; } public bool ShouldSerializeSecret() { return !string.IsNullOrEmpty(Secret); } }当Secret为 null 或空字符串时该属性会被忽略。这种机制在处理“根据运行状态决定某个字段是否输出”时非常方便。4.6.2 System.Text.Json 的替代方案System.Text.Json 没有直接等价物但有几种替代思路思路一统一使用JsonIgnore条件组合JsonIgnoreCondition适合简单的 null/默认值判断。思路二使用自定义转换器实现更复杂的条件判断。比如我们需要一个属性在特定情况下忽略可以包一层OptionalPropertyT类型或者直接在转换器里控制输出结构。下面用一个自定义转换器的简单思路说明public class Person { public string Name { get; set; } [JsonIgnore] public string? Secret { get; set; } public bool ShouldSerializeSecret !string.IsNullOrEmpty(Secret); }然后写一个自定义转换器在Write时手动判断public class PersonConverter : JsonConverterPerson { public override Person Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return JsonSerializer.DeserializePerson(ref reader, options); } public override void Write(Utf8JsonWriter writer, Person value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteString(name, value.Name); if (!string.IsNullOrEmpty(value.Secret)) { writer.WriteString(secret, value.Secret); } writer.WriteEndObject(); } }然后在注册转换器时使用var options new JsonSerializerOptions { Converters { new PersonConverter() } };这种方式比较繁琐但逻辑很直观。实际项目中也可以用 DTO数据传输对象提前做映射只输出需要的字段比自定义转换器更容易维护。对于只读输出场景我更推荐使用 DTO而不是把所有条件判断堆积在序列化层。4.7 枚举字符串转换4.7.1 Newtonsoft 的 StringEnumConverterNewtonsoft 中可以使用var settings new JsonSerializerSettings { Converters { new StringEnumConverter() } };也可以给属性添加[JsonConverter(typeof(StringEnumConverter))]。4.7.2 System.Text.Json 的 JsonStringEnumConverterSystem.Text.Json 内置了JsonStringEnumConvertervar options new JsonSerializerOptions { Converters { new JsonStringEnumConverter() } };如果希望枚举值为驼峰命名风格的字符串比如FirstItem变成firstItem从 .NET 8 开始可以传入命名策略var options new JsonSerializerOptions { Converters { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) } };在 ASP.NET Core 中可以全局注册。需要注意JsonStringEnumConverter默认会匹配枚举的[EnumMember]特性使用时可以先验证一下预期输出避免前后端字段定义不一致。4.8 动态 JSON 操作JObject 与 JsonNode 的对比4.8.1 Newtonsoft 的 JObjectNewtonsoft 的JObject非常强大可以直接读取、修改和遍历 JSON 数据using Newtonsoft.Json.Linq; var json {\name\:\张三\,\age\:20}; var obj JObject.Parse(json); obj[age] 21; obj[city] 北京; Console.WriteLine(obj.ToString());这种“拿到 JSON 当成文档对象操作”的体验在很多配置解析、接口转发场景中特别好用。4.8.2 System.Text.Json 的 JsonNode从 .NET 6 开始System.Text.Json 提供了JsonNode、JsonObject、JsonArray、JsonValue等一系列类型。基本用法using System.Text.Json.Nodes; var json {\name\:\张三\,\age\:20}; var node JsonNode.Parse(json); node[age] 21; node[city] 北京; Console.WriteLine(node.ToJsonString());从 API 形态上看JsonNode与JObject已经非常接近了。不过两者在索引器语义、类型转换、以及对 LINQ 的集成上仍有差异。如果你是重度 JSON 文档操作场景Newtonsoft 的JObject可能依然更顺手如果只是偶尔读几个字段JsonNode足够用。5. 完整实战改造一个包含多种序列化场景的 ASP.NET Core Web API这一节用一个 Web API 示例把前面提到的多个方案串起来包括全局配置、自定义 Converter、多态支持、忽略 null 和属性命名策略。5.1 创建项目结构dotnet new webapi -n SerializationDemo cd SerializationDemo如果模板创建时包含示例天气接口可以先删除无关文件保留基本结构。5.2 定义模型在Models文件夹中添加两个文件。Models/User.csusing System.Text.Json.Serialization; namespace SerializationDemo.Models; public class User { public int Id { get; set; } public string Name { get; set; } string.Empty; [JsonIgnore(Condition JsonIgnoreCondition.WhenWritingNull)] public string? Email { get; set; } public UserType Type { get; set; } public DateTime CreateTime { get; set; } } public enum UserType { Normal 0, Vip 1, Admin 2 }Models/Animal.csusing System.Text.Json.Serialization; namespace SerializationDemo.Models; [JsonDerivedType(typeof(Dog), dog)] [JsonDerivedType(typeof(Cat), cat)] public class Animal { public string Name { get; set; } string.Empty; } public class Dog : Animal { public bool CanBark { get; set; } } public class Cat : Animal { public bool CanCatchMouse { get; set; } }5.3 编写转换器在Converters文件夹中添加日期转换器。Converters/DateTimeConverter.csusing System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; namespace SerializationDemo.Converters; public class DateTimeConverter : JsonConverterDateTime { private readonly string _format; public DateTimeConverter(string format yyyy-MM-dd HH:mm:ss) { _format format; } public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType JsonTokenType.String DateTime.TryParseExact(reader.GetString(), _format, CultureInfo.InvariantCulture, DateTimeStyles.None, out var date)) { return date; } return reader.GetDateTime(); } public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString(_format, CultureInfo.InvariantCulture)); } }5.4 配置全局序列化选项在Program.cs中配置 MVC 的 JSON 选项using System.Text.Json; using System.Text.Json.Serialization; using SerializationDemo.Converters; var builder WebApplication.CreateBuilder(args); builder.Services.AddControllers() .AddJsonOptions(options { options.JsonSerializerOptions.PropertyNamingPolicy JsonNamingPolicy.CamelCase; options.JsonSerializerOptions.PropertyNameCaseInsensitive true; options.JsonSerializerOptions.DefaultIgnoreCondition JsonIgnoreCondition.WhenWritingNull; options.JsonSerializerOptions.Converters.Add(new DateTimeConverter(yyyy-MM-dd HH:mm:ss)); options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); }); var app builder.Build(); app.MapControllers(); app.Run();关键配置说明PropertyNamingPolicy JsonNamingPolicy.CamelCase输出属性名为驼峰命名。PropertyNameCaseInsensitive true反序列化时不区分大小写。DefaultIgnoreCondition JsonIgnoreCondition.WhenWritingNull全局忽略 null 字段。注册DateTimeConverter统一输出自定义日期格式。注册JsonStringEnumConverter枚举输出为字符串。5.5 编写测试接口Controllers/TestController.csusing Microsoft.AspNetCore.Mvc; using SerializationDemo.Models; namespace SerializationDemo.Controllers; [ApiController] [Route(api/test)] public class TestController : ControllerBase { [HttpPost(user)] public IActionResult GetUser() { var user new User { Id 1, Name 张三, Email null, Type UserType.Vip, CreateTime DateTime.Now }; return Ok(user); } [HttpPost(user/input)] public IActionResult InputUser(User user) { return Ok(new { user.Id, user.Name, user.Type, Message 接收成功 }); } [HttpGet(animal)] public IActionResult GetAnimal() { Animal dog new Dog { Name 旺财, CanBark true }; return Ok(dog); } }5.6 运行与验证启动项目dotnet run用 curl 或 Postman 请求/api/test/user预期输出类似{ id: 1, name: 张三, email: null }因为配置了忽略 nullemail字段应该不会出现。type会输出为字符串Vip或数字取决于你注册的枚举转换器。由于我们在Program.cs中注册了JsonStringEnumConvertertype会显示为Vip。再请求/api/test/animal{ $type: dog, name: 旺财, canBark: true }可以看到$type字段会被写入并且子类属性canBark能正常输出。请求/api/test/user/input时传入 JSON{ ID: 2, NAME: 李四, TYPE: Admin }因为开启了PropertyNameCaseInsensitive即使大写属性名也能正确绑定。枚举Admin也能被正确解析为UserType.Admin。6. 常见问题与排查思路问题现象常见原因解决思路反序列化后对象属性全是默认值属性名大小写不匹配或被[JsonIgnore]忽略开启PropertyNameCaseInsensitive检查属性和 JSON 字段名DateTime 格式变成 ISO 格式System.Text.Json 默认为 ISO 8601自定义JsonConverterDateTime输出中出现大量 null 字段未配置忽略 null设置DefaultIgnoreCondition JsonIgnoreCondition.WhenWritingNull遇到循环引用抛异常对象互相引用设置ReferenceHandler.IgnoreCycles或者改用 DTO枚举变成数字而不是字符串未注册枚举转换器注册JsonStringEnumConverter子类属性丢失未配置多态相关特性使用[JsonDerivedType]或在自定义转换器中处理反序列化 JSON 时报JsonException自定义 Converter 对格式识别失败在Read方法中增加容错处理增加Try-Catch和回退逻辑迁移后接口字段命名变化PropertyNamingPolicy不同统一配置JsonNamingPolicy.CamelCase或使用[JsonPropertyName]如果你在迁移过程中发现输出结果与 Newtonsoft 不一致建议先做一轮“对比测试”用同一组数据分别用两个库序列化再逐一检查差异。很多接口兼容性问题都能通过这种方式快速发现。7. 最佳实践与工程建议7.1 选择原则什么时候继续用 Newtonsoft如果项目满足以下条件之一不建议强行迁移到 System.Text.Json项目深度使用了JObject、JArray、JToken等动态 JSON API并且代码量很大。依赖了 Newtonsoft 的复杂ContractResolver自定义逻辑例如根据运行时类型动态决定序列化字段。第三方库或旧框架强依赖 Newtonsoft存在程序集绑定冲突。项目是从 .NET Framework 迁移到 .NET Core 的存量系统当前运行稳定迁移收益不大。7.2 什么时候考虑 System.Text.Json项目是全新开发的 .NET 6 应用。对性能、内存占用比较敏感。希望使用源生成Source Generation减少反射开销甚至为 AOT 发布做准备。期望减少第三方依赖让项目更“原生”。7.3 平滑迁移策略如果决定从 Newtonsoft 迁移到 System.Text.Json建议分几步走第一步统一项目中的 JSON 序列化入口不要散落各处直接调用JsonConvert。第二步在测试环境中写一个“双序列化对比工具”输入同样对象分别使用 Newtonsoft 和 System.Text.Json 序列化比较 JSON 文本差异确保字段名、格式、忽略规则一致。第三步为特殊的类型编写自定义 Converter优先保证功能兼容再做性能优化。第四步调整前端接口调用如果字段名或格式发生变化需要同步通知前端团队。7.4 序列化配置规范实际项目中建议把序列化配置集中管理而不是在每次调用时临时创建JsonSerializerOptions。每次创建JsonSerializerOptions都有额外开销而且容易遗漏配置项。常见做法是定义一个静态配置类using System.Text.Json; using System.Text.Json.Serialization; public static class JsonOptionsProvider { public static JsonSerializerOptions Default { get; } Create(); private static JsonSerializerOptions Create() { var options new JsonSerializerOptions { PropertyNamingPolicy JsonNamingPolicy.CamelCase, PropertyNameCaseInsensitive true, DefaultIgnoreCondition JsonIgnoreCondition.WhenWritingNull, ReferenceHandler ReferenceHandler.IgnoreCycles, WriteIndented false }; options.Converters.Add(new JsonStringEnumConverter()); return options; } }这样项目中只要使用同一个JsonOptionsProvider.Default就能保证序列化风格一致。7.5 安全建议反序列化时永远不要相信外部输入。虽然 System.Text.Json 的[JsonDerivedType]比 Newtonsoft 的TypeNameHandling安全但不代表可以接受任意类型。尽量避免使用TypeNameHandling.All处理不受信任的数据。自定义 Converter 中若有Try-Catch不要吞掉所有异常至少要让错误在日志中可见。生产环境修改序列化配置前先在测试环境用真实规模数据验证。8. 总结System.Text.Json 和 Newtonsoft 不是简单的替代关系。System.Text.Json 在性能和内存消耗上更优也更符合现代 .NET 发展方向Newtonsoft 则胜在功能全面和 API 灵活。对于大多数常见场景System.Text.Json 通过自定义 Converter、特性配置和JsonSerializerOptions都能给出不错的补救方案只是需要开发者多写一点代码。如果你正准备做技术选型可以结合团队熟悉程度和项目实际需求决定。如果项目已经稳定运行在 Newtonsoft 上不必为了换而换如果项目还在早期阶段直接选择 System.Text.Json 并统一配置后续维护成本会更低。希望这篇文章能帮你理清两者差异也欢迎在评论区聊聊你项目中还遇到过哪些 System.Text.Json 的“坑”我后面可以继续整理对应的解决方案。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门