System.Text.Json 默认不兼容 Newtonsoft 的常见用法,需手动配置处理私有字段、循环引用、非 ISO 日期、大小写不匹配等问题;典型 JsonException 多因类型契约断裂,如 null 赋值给非可空 int、字段名大小写不一致、日期格式不符 ISO 8601 等。

System.Text.Json 不是“开箱即用”的 Newtonsoft 替代品,它默认不处理私有字段、循环引用、非 ISO 日期、大小写不匹配等常见现实场景——你得手动补配置,否则一跑就崩。
JsonSerializer.Deserialize 报 JsonException 怎么快速定位
这不是语法错误,而是类型契约断裂。最常触发的几个点:
-
JsonException: The JSON value could not be converted to System.Int32→ JSON 里是"age": null,而 C# 属性是int Age { get; set; };改成int?或加[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - 字段名大小写不一致:JSON 是
"userName",C# 类写的是public string Username { get; set; }→ 必须配new JsonSerializerOptions { PropertyNameCaseInsensitive = true } - 日期字段是
"2023/10/05"或"2023-10-05"→System.Text.Json只认完整 ISO 8601(如"2023-10-05T00:00:00Z"),需注册自定义JsonConverter<datetime></datetime> - 传入
null或空白字符串 → 先做string.IsNullOrWhiteSpace(json)检查,否则直接报The input does not contain any JSON tokens
想序列化私有字段或只读属性必须显式开开关
默认只序列化 public get/set 属性,private int _age 和 public int Age => _age 都不会出现。要让它工作:
- 启用字段访问:
IncludeFields = true - .NET 6+ 支持只读属性:
AllowReadOnlyProperties = true - 若需驼峰命名,加
PropertyNamingPolicy = JsonNamingPolicy.CamelCase - 注意:这些选项只影响序列化行为,反序列化时仍需确保构造逻辑可行(比如只读属性需有对应构造函数或
[JsonConstructor])
示例配置:
var options = new JsonSerializerOptions
{
IncludeFields = true,
AllowReadOnlyProperties = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};结构不确定时别硬套 Deserialize,改用 JsonDocument
当你面对第三方 API 返回、日志片段、配置片段,或只关心其中一两个字段时,强类型反序列化极易因字段缺失、空值嵌套、类型漂移而崩溃。
-
JsonDocument.Parse(json)构建只读树结构,内存开销小,适合一次解析、多次读取 - 必须用
using块或手动调.Dispose(),否则可能内存泄漏 - 访问路径务必用
TryGetProperty("xxx", out var elem)判断存在性;直接GetProperty("xxx")遇到缺失字段就抛KeyNotFoundException - 宽松解析支持注释和尾逗号:
ReadCommentHandling = JsonCommentHandling.Skip和AllowTrailingCommas = true(仅对反序列化有效)
DateTime 时区和格式是跨服务场景下最隐蔽的坑
默认把 DateTime 当作本地时间处理,序列化成无时区标识的 "2023-04-05T10:30:00",反序列化也按本地时区解释——不同服务器时区不一致时,时间会偏移。
- 首选方案:统一用
DateTimeOffset,它自带偏移量,序列化结果如"2023-04-05T10:30:00+08:00" - 若必须用
DateTime,且输入格式非标准(如"2024-05-12"),必须注册自定义JsonConverter<datetime></datetime>,不能靠选项兜底 -
JsonSerializerOptions的DefaultIgnoreCondition对DateTime无效,null 值仍会触发异常,得靠可空类型或 converter 拦截
真正麻烦的不是写错一行代码,而是某个字段在开发环境正常、测试环境飘移、生产环境凌晨三点突然出错——这种问题往往卡在时区、空值、大小写这三处细节上,而不是逻辑本身。


















