
System.Text.Json实用指南与技巧
System.Text.Json是.NET Core 3.0及更高版本中内置的高性能JSON序列化和反序列化库。遵循以下最佳实践可以帮助你充分利用其优势,同时避免常见陷阱。
一、性能优化
1. 重用JsonSerializerOptions实例:
JsonSerializerOptions的创建和初始化有一定开销,因为它需要验证和缓存配置。强烈建议在应用程序的生命周期内尽可能重用同一个JsonSerializerOptions实例。推荐的做法是使用静态只读字段或通过依赖注入注册为单例。
2. 使用异步方法进行I/O操作:
当处理流(例如FileStream,NetworkStream,HttpResponse.Body)时,优先使用SerializeAsync和DeserializeAsync方法。这可以避免阻塞线程,提高应用程序的吞吐量和响应性,特别是在Web服务器和UI应用程序中。
3. 使用Utf8JsonReader和Utf8JsonWriter处理大型JSON或追求极致性能:
对于需要逐个令牌处理非常大的JSON文件或需要最大限度减少内存分配的场景,可以使用底层的Utf8JsonReader(读取)和Utf8JsonWriter(写入)。这提供了最高的性能和最低的内存占用,但需要编写更底层的代码,也更复杂。
4. 利用源生成器(Source Generators)(.NET 6+):
源生成器在编译时生成序列化和反序列化逻辑,避免了运行时的反射和元数据查找,可以显著提高性能并减少内存分配。需要定义一个继承自JsonSerializerContext的分部类,并用[JsonSerializable]属性标记需要处理的类型。
二、正确性与健壮性
1. 处理大小写:
默认情况下,System.Text.Json是大小写敏感的。如果需要忽略JSON属性名的大小写,请设置JsonSerializerOptions的PropertyNameCaseInsensitive=true。使用JsonSerializerOptions的PropertyNamingPolicy来统一C#属性名和JSON属性名之间的转换。
2. 明确指定属性名称:
如果C#属性名与JSON属性名不匹配,使用[JsonPropertyName(“json_name”)]特性来明确指定映射。
3. 控制null值的序列化:
默认情况下,值为null的属性会被序列化。如果想忽略null值属性,可以设置JsonSerializerOptions的DefaultIgnoreCondition为WhenWritingNull。还可以使用WhenWritingDefault来忽略值为默认值的属性。
4. 处理枚举:
默认情况下,枚举被序列化为数字。若要将枚举序列化为字符串,需要添加JsonStringEnumConverter到JsonSerializerOptions的Converters集合中,或在特定枚举属性上使用[JsonConverter(typeof(JsonStringEnumConverter))]。
5. 处理无法直接映射的类型:
对于System.Text.Json本身不支持或需要自定义逻辑的类型,需要创建自定义转换器并继承自JsonConverter。将自定义转换器添加到JsonSerializerOptions的Converters集合中,或在特定属性/类上使用[JsonConverter(typeof(MyCustomConverter))]特性。
6. 错误处理:
在调用Deserialize时,使用try-catch块捕获JsonException来处理无效的JSON或类型不匹配等错误。
三、配置管理
1. 集中配置JsonSerializerOptions:
在应用程序中(特别是在ASP.NET Core中),通过DI容器配置和注入JsonSerializerOptions是管理共享配置的最佳方式。在ASP.NET Core中,可以通过Configure或AddJsonOptions来配置全局的JSON选项。
2. 使用JsonSerializerDefaults.Web:
.NET 5+引入了JsonSerializerDefaults.Web,它提供了一组适合Web应用程序场景的默认选项。可以以此为基础创建JsonSerializerOptions实例。
四、安全性考量
1. 反序列化风险:
反序列化来自不受信任来源的JSON数据可能存在安全风险。设置JsonSerializerOptions的MaxDepth来限制反序列化的最大对象深度。验证反序列化后的数据状态是否符合预期。
五、代码可维护性
1. 使用POCO:定义清晰的、与JSON结构对应的POCO类,使代码易于理解和维护。
2. 合理使用特性:使用[JsonPropertyName]、[JsonIgnore]、[JsonInclude]、[JsonConverter]等特性来明确表达序列化契约。
3. 自定义转换器应保持简单:自定义转换器应专注于单一类型的转换逻辑,保持其简洁和可测试性。
总结关键点:
1. 重用JsonSerializerOptions以获得最佳性能。
2. 优先使用异步API(SerializeAsync/DeserializeAsync)处理流。
3. 考虑使用源生成器(JsonSerializerContext)以进一步提升性能和减少内存占用(.NET 6+)。
4. 通过PropertyNameCaseInsensitive和PropertyNamingPolicy正确处理属性名称大小写。使用[JsonPropertyName]和[JsonIgnore]等特性明确控制序列化行为。需要时使用JsonConverter处理复杂类型或自定义格式。注意反序列化安全,设置MaxDepth并验证输入。在ASP.NET Core中利用框架提供的JsonOptions配置来提高开发效率和安全性。
