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

.NET6中使用Microsoft JsonSerializer实现属性必填校验

在.NET6中用System.Text.Json实现必填属性检测

由于.NET7才引入[JsonRequired]特性,在.NET6环境下要实现反序列化时检测缺失必填属性的功能,可以通过以下几种方式实现:

方法一:自定义JsonConverter验证必填属性

针对需要校验的实体类编写自定义转换器,在反序列化过程中追踪必填属性是否在JSON中存在,不存在则抛出异常。

示例代码

public class innerJModel {
    public int someProp { get; set; }
}

public class innerJModelConverter : JsonConverter<innerJModel> {
    public override innerJModel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
        if (reader.TokenType != JsonTokenType.StartObject) {
            throw new JsonException("JSON格式错误,预期对象起始标识");
        }

        var model = new innerJModel();
        bool somePropFound = false;

        while (reader.Read()) {
            if (reader.TokenType == JsonTokenType.EndObject) break;
            
            if (reader.TokenType == JsonTokenType.PropertyName) {
                string propName = reader.GetString();
                reader.Read();

                if (propName.Equals("someProp", StringComparison.OrdinalIgnoreCase)) {
                    model.someProp = reader.GetInt32();
                    somePropFound = true;
                }
            }
        }

        if (!somePropFound) {
            throw new JsonException("JSON中缺少必填属性: someProp");
        }

        return model;
    }

    public override void Write(Utf8JsonWriter writer, innerJModel value, JsonSerializerOptions options) {
        JsonSerializer.Serialize(writer, value, options);
    }
}

public class JModel {
    public innerJModel innerJModel { get; set; }
}

public static void test() {
    JsonSerializerOptions FromJson_JsonSerOpts = new JsonSerializerOptions(JsonSerializerDefaults.General) {
        AllowTrailingCommas = true,
        ReadCommentHandling = JsonCommentHandling.Skip,
        IncludeFields = false,
    };
    FromJson_JsonSerOpts.Converters.Add(new innerJModelConverter());

    JsonSerializerOptions ToJson_JsonSerOpts = new JsonSerializerOptions(JsonSerializerDefaults.General) {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
    };

    string jsonStr = @"{""innerJModel"":{""someProp"":12}}";
    var serRes = JsonSerializer.Deserialize<JModel>(jsonStr, FromJson_JsonSerOpts);
    Console.WriteLine(serRes.innerJModel?.someProp);
    Console.WriteLine(JsonSerializer.Serialize(serRes, ToJson_JsonSerOpts));

    string jsonStr2 = @"{""innerJModel"":{}}";
    try {
        var serRes2 = JsonSerializer.Deserialize<JModel>(jsonStr2, FromJson_JsonSerOpts);
        Console.WriteLine(JsonSerializer.Serialize(serRes2, ToJson_JsonSerOpts));
    } catch (JsonException ex) {
        Console.WriteLine($"反序列化失败: {ex.Message}");
    }
}

方法二:反序列化后手动验证模型

在反序列化完成后,对模型的必填属性进行手动校验,不符合要求则抛出异常,适合简单模型场景。

示例代码

public class innerJModel {
    public int someProp { get; set; }

    public void Validate() {
        // 若0是非法输入,可直接判断默认值;若0合法,需结合JsonElement判断属性是否存在
        if (someProp == default) {
            throw new InvalidOperationException("属性someProp为必填项");
        }
    }
}

public class JModel {
    public innerJModel innerJModel { get; set; }

    public void Validate() {
        if (innerJModel == null) {
            throw new InvalidOperationException("属性innerJModel为必填项");
        }
        innerJModel.Validate();
    }
}

public static void test() {
    JsonSerializerOptions FromJson_JsonSerOpts = new JsonSerializerOptions(JsonSerializerDefaults.General) {
        AllowTrailingCommas = true,
        ReadCommentHandling = JsonCommentHandling.Skip,
        IncludeFields = false,
    };
    JsonSerializerOptions ToJson_JsonSerOpts = new JsonSerializerOptions(JsonSerializerDefaults.General) {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
    };

    string jsonStr = @"{""innerJModel"":{""someProp"":12}}";
    var serRes = JsonSerializer.Deserialize<JModel>(jsonStr, FromJson_JsonSerOpts);
    serRes.Validate();
    Console.WriteLine(serRes.innerJModel?.someProp);
    Console.WriteLine(JsonSerializer.Serialize(serRes, ToJson_JsonSerOpts));

    string jsonStr2 = @"{""innerJModel"":{}}";
    try {
        var serRes2 = JsonSerializer.Deserialize<JModel>(jsonStr2, FromJson_JsonSerOpts);
        serRes2.Validate();
        Console.WriteLine(JsonSerializer.Serialize(serRes2, ToJson_JsonSerOpts));
    } catch (InvalidOperationException ex) {
        Console.WriteLine($"验证失败: {ex.Message}");
    }
}

方法三:结合JsonElement严格校验属性存在性

先将JSON解析为JsonElement,直接检查必填属性是否存在,避免默认值干扰,适合需要严格校验属性存在性的场景。

示例代码

public static void test() {
    JsonSerializerOptions FromJson_JsonSerOpts = new JsonSerializerOptions(JsonSerializerDefaults.General) {
        AllowTrailingCommas = true,
        ReadCommentHandling = JsonCommentHandling.Skip,
        IncludeFields = false,
    };
    JsonSerializerOptions ToJson_JsonSerOpts = new JsonSerializerOptions(JsonSerializerDefaults.General) {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
    };

    string jsonStr2 = @"{""innerJModel"":{}}";
    try {
        var jsonElement = JsonSerializer.Deserialize<JsonElement>(jsonStr2, FromJson_JsonSerOpts);
        
        if (!jsonElement.TryGetProperty("innerJModel", out var innerElement)) {
            throw new JsonException("缺少必填属性: innerJModel");
        }
        if (!innerElement.TryGetProperty("someProp", out _)) {
            throw new JsonException("缺少必填属性: someProp");
        }

        var serRes2 = JsonSerializer.Deserialize<JModel>(jsonStr2, FromJson_JsonSerOpts);
        Console.WriteLine(JsonSerializer.Serialize(serRes2, ToJson_JsonSerOpts));
    } catch (JsonException ex) {
        Console.WriteLine($"反序列化失败: {ex.Message}");
    }
}

方案选择建议

  • 自定义转换器:适合全局统一处理,侵入性低,无需修改实体类逻辑;
  • 手动验证:适合简单模型,实现成本低,逻辑直观;
  • JsonElement解析:适合需要严格判断属性是否存在的场景,避免默认值误判。

内容的提问来源于stack exchange,提问作者Andrea Bardelli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 20:08:29