如何让Newtonsoft.Json反序列化时构造参数不匹配抛出异常
问题根因
你当前的配置无法捕获异常是因为两个配置的生效范围不覆盖该场景:
MissingMemberHandling.Error仅会在JSON中出现目标类完全不存在的成员时抛出异常,你的场景中JSON的a对应类中存在A属性,不属于缺失成员,因此不会触发。- 加在
A上的[JsonProperty(Required = Required.Always)]未生效,是因为Newtonsoft.Json反序列化时优先走带参构造函数实例化对象,对于只读属性会默认认为已经在构造阶段完成赋值,不会再对属性做必填校验。
可行解决方案
方案1:构造参数加必填校验(侵入式,改造成本低)
给构造函数的每个参数添加[JsonProperty(Required = Required.Always)]特性,框架会强制校验JSON中是否存在和构造参数名匹配的键,不存在就直接抛出异常:
public class Foo { public Foo([JsonProperty(Required = Required.Always)]int b, [JsonProperty(Required = Required.Always)]int c) { A = b; C = c; } public int A { get; } public int C { get; } }
你的测试JSON中不存在b字段,反序列化时会直接抛出JsonSerializationException: Required property 'b' not found in JSON. Path '',符合预期。
方案2:全局自定义契约解析器(无侵入,适合批量校验)
如果不想修改业务类代码,可以自定义契约解析器,在反序列化完成后统一校验所有标记了必填的属性是否为类型默认值:
public class RequiredReadOnlyPropertiesContractResolver : DefaultContractResolver { protected override JsonObjectContract CreateObjectContract(Type objectType) { var contract = base.CreateObjectContract(objectType); // 反序列化完成后触发必填属性校验 contract.OnDeserializedCallbacks.Add((o, context) => { foreach (var prop in contract.Properties.Where(p => p.Required != Required.Default)) { var value = prop.ValueProvider.GetValue(o); // 可根据业务需求扩展其他值类型的默认值判断逻辑 if (value == null || (value is int intVal && intVal == 0) || (value is long longVal && longVal == 0) || (value is Guid guidVal && guidVal == Guid.Empty)) { throw new JsonSerializationException($"Required property '{prop.PropertyName}' is not correctly bound, value is type default."); } } }); return contract; } }
使用时将自定义解析器注册到序列化配置中即可:
JsonSerializerSettings settings = new JsonSerializerSettings(); settings.MissingMemberHandling = MissingMemberHandling.Error; settings.ContractResolver = new RequiredReadOnlyPropertiesContractResolver();
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

