设置MissingMemberHandling.Error后,带JsonIgnore的属性未抛序列化异常怎么办?
问题原因解析
[JsonIgnore]特性会告知Newtonsoft.Json序列化器完全忽略目标属性,涵盖序列化和反序列化的全流程。而MissingMemberHandling.Error配置仅对目标类中不存在的成员生效——被[JsonIgnore]标记的属性属于「存在但被序列化器主动忽略」的范畴,不会被判定为「缺失成员」,因此不会触发JsonSerializationException。
解决方案
方案1:移除[JsonIgnore],通过方法控制序列化+限制反序列化
若你需要同时满足:
- 序列化对象时不输出
DeletedDate - 反序列化时Json中出现
DeletedDate则抛出异常
可修改代码如下:
public class Account { public string FullName { get; set; } public bool Deleted { get; set; } // 移除[JsonIgnore],标记该属性仅允许内部赋值 [JsonProperty(Access = JsonPropertyAccess.ReadOnly)] public bool DeletedDate { get; set; } // 序列化时跳过该属性 public bool ShouldSerializeDeletedDate() { return false; } }
反序列化时,若Json中存在DeletedDate字段,序列化器会因属性为只读而抛出JsonSerializationException。
方案2:自定义ContractResolver检测被忽略字段
创建自定义解析器,记录所有被[JsonIgnore]标记的成员,反序列化时检查Json中是否存在这些字段,若存在则主动抛出异常:
public class StrictIgnoreContractResolver : DefaultContractResolver { private readonly HashSet<string> _ignoredMemberNames = new HashSet<string>(); protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); // 记录被JsonIgnore标记的成员名称 if (member.GetCustomAttribute<JsonIgnoreAttribute>() != null) { _ignoredMemberNames.Add(property.PropertyName); } return property; } public override JsonContract ResolveContract(Type type) { var contract = base.ResolveContract(type); if (contract is JsonObjectContract objectContract) { objectContract.OnDeserializingCallbacks.Add((obj, context) => { var reader = context.Reader as JsonTextReader; if (reader == null) return; // 加载Json并检查是否包含被忽略的字段 var jsonObj = JObject.Load(reader); foreach (var ignoredName in _ignoredMemberNames) { if (jsonObj.ContainsKey(ignoredName)) { throw new JsonSerializationException($"Json中包含不允许的字段: {ignoredName}"); } } // 重置Reader位置,确保后续反序列化正常执行 context.Reader = new JsonTextReader(new StringReader(jsonObj.ToString())); }); } return contract; } }
使用该解析器反序列化:
try { var obj = JsonConvert.DeserializeObject<Account>(json, new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error, ContractResolver = new StrictIgnoreContractResolver() }); } catch (JsonSerializationException ex) { Console.WriteLine(ex.Message); // 输出"Json中包含不允许的字段: DeletedDate" }
方案3:提前用JsonSchema验证Json结构
通过Newtonsoft.Json.Schema生成类的校验规则,强制限制Json不能包含额外字段:
// 需先安装Newtonsoft.Json.Schema NuGet包 var schemaGenerator = new JSchemaGenerator(); var accountSchema = schemaGenerator.Generate(typeof(Account)); // 禁止Json包含Schema定义外的字段 accountSchema.AdditionalProperties = false; // 验证输入Json var jsonObj = JObject.Parse(json); var validationErrors = new List<ValidationError>(); bool isValid = jsonObj.IsValid(accountSchema, validationErrors); if (!isValid) { foreach (var error in validationErrors) { Console.WriteLine(error.Message); // 提示"属性DeletedDate未被定义" } throw new JsonSerializationException("Json包含非法字段"); } // 验证通过后执行反序列化 var obj = JsonConvert.DeserializeObject<Account>(json, new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error });
内容的提问来源于stack exchange,提问作者Vikram Sudhini
相关产品推荐
相关产品推荐

