推荐使用 System.Text.Json 序列化对象,它是 .NET Core 3.0+ 内置高性能 JSON 库,无需额外 NuGet,结果紧凑、安全且 UTF-8 友好;需注意配置差异、循环引用处理、特性迁移(如 [JsonPropertyName])、类型兼容性及 null/ 默认值控制策略。

用 System.Text.Json 序列化对象最稳妥
默认推荐走 System.Text.Json,它是 .NET Core 3.0+ 内置的高性能 JSON 库,无需额外 NuGet,序列化结果紧凑、安全(默认不序列化私有字段和循环引用),且对 UTF-8 友好。
常见错误是直接用 JsonConvert.SerializeObject(来自 Newtonsoft.Json)却没装包,或者混用两个库导致配置不一致。
-
JsonSerializer.Serialize<T>(obj)是最简调用,适合大多数场景 - 需要控制格式时加
JsonSerializerOptions:比如options.WriteIndented = true美化输出,options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase转驼峰 - 若实体含只读属性或私有 setter,需显式启用:
options.IgnoreReadOnlyProperties = false(默认为true) - 遇到
NotSupportedException: A possible object cycle was detected,不是要关循环检测,而是检查是否真有循环引用;真需要忽略,设options.ReferenceHandler = ReferenceHandler.Preserve(仅限 .NET 6+)
Newtonsoft.Json 还能用,但要注意版本和配置差异
老项目还在用 Newtonsoft.Json(即 JsonConvert)很常见,它更灵活,但默认行为和 System.Text.Json 不同——比如默认序列化私有字段、支持更多类型、循环引用处理更宽松。
容易踩的坑是:升级到 .NET 6/7 后仍沿用旧习惯,结果发现日期格式变了(System.Text.Json 默认 ISO 8601,Newtonsoft 默认是 "/Date(123)/" 风格),或空字符串被序列化成 null(因 NullValueHandling.Ignore 配置未同步)。
- 用
JsonConvert.SerializeObject(obj, new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.IsoDateFormat})统一日期格式 - 若想让
string.Empty不被跳过,确保没设NullValueHandling.Ignore,或改用DefaultValueHandling.Ignore - 迁移时注意
[JsonProperty("xxx")]在System.Text.Json中对应的是[JsonPropertyName("xxx")],别漏改特性
序列化失败时先看异常堆栈里的具体类型
报错信息里带 NotSupportedException 或 InvalidOperationException 很常见,但真正卡点往往藏在内层类型上——比如你序列化一个 List<MyClass>,实际崩在 MyClass 里某个 DateTimeOffset? 字段(.NET 5 以下不支持),或某个自定义类没无参构造函数(Newtonsoft 要求,System.Text.Json 默认不要求但反序列化时要)。
- 把对象先简化:只留 1–2 个基础字段,确认能跑通,再逐步加回
- 检查字段类型是否在目标框架中受支持(如
System.Drawing.Color、DBNull、Pointer类型基本都不行) - 若用 ASP.NET Core,默认 MVC 的 JSON 输出走
System.Text.Json,但你手动调JsonConvert就可能触发混合行为,导致同一对象在 API 返回和日志打印里格式不一致
别忘了 null 值和默认值的处理逻辑
JSON 字符串里要不要出现 "name": null 或 "count": 0,不是由语言决定的,而是由序列化器的选项和属性上的特性共同控制。很多人以为加了 [JsonIgnore] 就万事大吉,其实 System.Text.Json 和 Newtonsoft 对它的响应方式不同。
-
[JsonIgnore]在两者中都生效,但System.Text.Json还认[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]这种细粒度条件(.NET 5+) - 想让
int? count = null不出现在 JSON 里,Newtonsoft 用NullValueHandling.Ignore;System.Text.Json则需options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - 默认值(如
public bool IsActive {get; set;} = true)不会自动省略,除非加[DefaultValue(true)]并配合对应选项(Newtonsoft 支持,System.Text.Json不支持该特性)
字段级控制比全局选项更可靠,尤其当一个类里有些字段要保留 null、有些要忽略时。别指望靠“统一配一个选项”解决所有问题。