.NET 6 JsonSerializer.DeserializeAsync null赋值非空属性异常解决方法
问题原因
System.Text.Json 默认存在以下行为,是该问题的核心诱因:
- 不会自动识别
[Required]这类数据注解特性,默认不会执行非空校验逻辑 - C# 定义的非空引用类型约束属于编译期检查,运行时序列化器不会主动拦截null赋值操作
- 反序列化时如果JSON缺失构造函数对应的参数,会默认传入null作为参数值,若构造函数内无null校验逻辑,就会直接把null赋值给声明为非空的属性
修复方案
根据项目使用的.NET版本,选择对应方案即可:
.NET 7及以上版本(最优方案)
直接配置JsonSerializerOptions的两个参数即可实现预期效果,无需修改实体类代码:
var jsonOptions = new JsonSerializerOptions { // 识别C#非空引用类型注解,非空属性/参数收到null值时直接抛出JsonException RespectNullableAnnotations = true, // 强制构造函数定义的必填参数不可缺失,JSON缺省对应字段时直接抛出异常 RespectRequiredConstructorParameters = true }; // 反序列化时传入上述配置即可 var result = await JsonSerializer.DeserializeAsync<ArchiveData>(requestStream, jsonOptions);
配置生效后,只要JSON缺失必填字段、或给非空字段传递null值,都会直接抛出异常,不会再出现非空属性被赋值为null的情况。
.NET 6及以下版本
低版本System.Text.Json没有上述两个内置配置,通过两步实现需求:
- 给实体类构造函数添加null校验,拦截传入的null值:
[JsonConstructor] public ArchiveData(long[] time, SensorArchiveValues[] sensorsArchiveValues) { Time = time ?? throw new ArgumentNullException(nameof(time), "time字段不可为null"); SensorsArchiveValues = sensorsArchiveValues ?? throw new ArgumentNullException(nameof(sensorsArchiveValues), "sensorsArchiveValues为必填字段"); }
- 反序列化完成后手动触发数据注解校验,让
[Required]特性生效:
var archiveData = await JsonSerializer.DeserializeAsync<ArchiveData>(requestStream); // 执行全属性校验,[Required]标记的属性为null时会抛出ValidationException var validationContext = new ValidationContext(archiveData); Validator.ValidateObject(archiveData, validationContext, validateAllProperties: true);
如果你是在ASP.NET Core接口中通过模型绑定直接接收参数(而非手动读取请求流调用反序列化),框架会自动执行上述校验逻辑,无需手动编写校验代码。
补充说明
代码中添加的[Required]特性属于System.ComponentModel.DataAnnotations下的数据注解,仅在ASP.NET Core模型绑定流程、或手动调用Validator类时生效,JsonSerializer本身不会主动解析执行该特性的校验逻辑,这也是加了特性依然不生效的核心原因。
内容的提问来源于stack exchange,提问作者hheimerd
相关产品推荐
相关产品推荐

