You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

设置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 08:32:21