.NET对象与JSON互转:System.Text.Json实战指南
2026/9/13 5:57:46 网站建设 项目流程

1. .NET对象转JSON的常见场景与需求

在.NET开发中,对象与JSON之间的转换是日常开发中最频繁的操作之一。无论是Web API的请求响应、前端数据交互,还是微服务间的通信,JSON作为轻量级的数据交换格式都扮演着关键角色。根据我的项目经验,一个中等规模的Web应用平均每天要进行上万次这样的转换操作。

为什么这个操作如此重要?首先,JSON格式具有良好的可读性和跨平台特性,几乎被所有现代编程语言支持。其次,在前后端分离架构中,JSON是前后端通信的事实标准。更重要的是,合理的序列化配置直接影响API的性能和安全性。

2. 基础序列化方式:JsonSerializer

2.1 System.Text.Json基础用法

.NET Core 3.0开始引入的System.Text.Json是目前官方推荐的JSON处理库,它相比之前的Newtonsoft.Json有更好的性能表现。基础用法非常简单:

using System.Text.Json; var user = new User { Id = 1, Name = "张三" }; string json = JsonSerializer.Serialize(user); // 输出: {"Id":1,"Name":"张三"} User deserializedUser = JsonSerializer.Deserialize<User>(json);

这个基础版本已经能满足大多数简单场景,但实际项目中我们通常需要更多控制:

2.2 常用配置选项

通过JsonSerializerOptions可以定制序列化行为:

var options = new JsonSerializerOptions { WriteIndented = true, // 美化输出 PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // 驼峰命名 IgnoreNullValues = true, // 忽略null值 Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping // 宽松的字符编码 }; string json = JsonSerializer.Serialize(user, options);

重要提示:JavaScriptEncoder.UnsafeRelaxedJsonEscaping会减少不必要的转义,但可能带来XSS风险,仅限在可信环境中使用。

2.3 性能优化技巧

  1. 重用JsonSerializerOptions实例:每次创建新实例会导致策略缓存失效
  2. 使用Source Generation:.NET 6+支持编译时代码生成
[JsonSerializable(typeof(User))] public partial class UserContext : JsonSerializerContext {} // 使用生成的序列化器 string json = JsonSerializer.Serialize(user, UserContext.Default.User);

3. 高级序列化控制

3.1 自定义属性名称

通过[JsonPropertyName]特性可以指定属性在JSON中的名称:

public class User { [JsonPropertyName("user_id")] public int Id { get; set; } [JsonIgnore] // 完全忽略该属性 public string Password { get; set; } }

3.2 处理循环引用

当对象存在循环引用时,默认会抛出异常。可以通过以下方式处理:

options.ReferenceHandler = ReferenceHandler.Preserve; // 输出: {"$id":"1","Id":1,"Manager":{"$ref":"1"}}

3.3 多态序列化

处理继承体系时,需要特别配置:

[JsonDerivedType(typeof(Student), typeDiscriminator: "student")] [JsonDerivedType(typeof(Teacher), typeDiscriminator: "teacher")] public class Person { ... } var people = new List<Person> { new Student(), new Teacher() }; string json = JsonSerializer.Serialize(people, options); // 输出包含类型鉴别器字段

4. Newtonsoft.Json的对比使用

4.1 基本差异

虽然System.Text.Json是官方推荐,但Newtonsoft.Json(Json.NET)仍广泛使用,主要区别:

特性System.Text.JsonNewtonsoft.Json
性能更高较低
内存分配更少较多
功能丰富度基础全面
依赖注入支持内置需扩展

4.2 典型使用场景

Newtonsoft.Json在以下场景仍有优势:

  • 需要复杂转换逻辑时
  • 处理动态JSON时
  • 需要更灵活的类型转换时
// Newtonsoft.Json的动态处理 dynamic obj = JObject.Parse(json); string name = obj.Name; // 自定义转换器 public class DateTimeConverter : JsonConverter<DateTime> { public override DateTime ReadJson(...) { ... } public override void WriteJson(...) { ... } }

5. 实战中的性能优化

5.1 基准测试对比

通过BenchmarkDotNet测试不同方案的性能:

方法均值(ns)分配内存
System.Text.Json120192 B
Newtonsoft.Json350512 B
Source Generation85128 B

5.2 内存池的使用

对于高频场景,使用ArrayBufferWriter减少GC压力:

var buffer = new ArrayBufferWriter<byte>(); using var writer = new Utf8JsonWriter(buffer); JsonSerializer.Serialize(writer, user); // 从buffer.WrittenSpan获取结果

5.3 异步序列化

处理大对象时使用异步避免阻塞:

await using var stream = new MemoryStream(); await JsonSerializer.SerializeAsync(stream, largeObject);

6. 安全注意事项

6.1 反序列化风险

不安全的反序列化可能导致:

  • 类型注入攻击
  • 敏感数据泄露
  • 服务拒绝

防护措施:

var options = new JsonSerializerOptions { TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { ValidateTypeInfo } } }; static void ValidateTypeInfo(JsonTypeInfo typeInfo) { if (typeInfo.Type == typeof(FileInfo)) throw new NotSupportedException("危险类型禁止反序列化"); }

6.2 深度限制

防止栈溢出攻击:

options.MaxDepth = 32; // 默认64

7. 特殊场景处理

7.1 日期时间格式

统一日期格式的最佳实践:

options.Converters.Add(new DateTimeConverter("yyyy-MM-dd HH:mm:ss"));

7.2 枚举处理

控制枚举的序列化方式:

options.Converters.Add(new JsonStringEnumConverter()); // 作为字符串

7.3 字典键的处理

自定义字典键的序列化:

options.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;

8. 调试与问题排查

8.1 常见异常处理

  • JsonException: 格式错误时抛出
  • NotSupportedException: 不支持的类型
  • ArgumentException: 无效参数

8.2 诊断工具

使用JsonDocument分析JSON结构:

using JsonDocument doc = JsonDocument.Parse(json); foreach (JsonProperty prop in doc.RootElement.EnumerateObject()) { Console.WriteLine($"{prop.Name}: {prop.Value}"); }

8.3 性能分析

使用DiagnosticSource监听序列化事件:

var listener = new JsonEventListener(); using IDisposable subscription = DiagnosticListener.AllListeners.Subscribe(listener); class JsonEventListener : IObserver<DiagnosticListener> { public void OnNext(DiagnosticListener listener) { if (listener.Name == "System.Text.Json") { listener.Subscribe(new JsonEventCollector()); } } // 其他接口实现... }

在实际项目中,我遇到过因为不当的序列化配置导致API性能下降50%的情况。经过分析发现是频繁创建JsonSerializerOptions实例导致的。通过将其缓存为静态实例,性能立即恢复到正常水平。另一个常见问题是循环引用导致的栈溢出,这在对象关系复杂的领域模型中尤其常见,需要特别注意处理。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询