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

使用自定义System.Text.Json转换器时如何强制必填属性

自定义System.Text.Json转换器时如何强制[JsonRequired]校验?

当使用System.Text.Json默认转换器时,标记[JsonRequired]的属性若在JSON中缺失,反序列化会正常抛出JsonException。但自定义JsonConverter后,默认的必填校验逻辑不会自动执行,导致缺失必填属性时仍能成功反序列化对象。以下是针对你的代码的解决办法:

解决步骤

  1. 提取必填属性元数据:在转换器初始化阶段,获取目标类型中标记了[JsonRequired]的属性名称。
  2. 跟踪已处理的必填属性:反序列化过程中,记录哪些必填属性已被读取并赋值。
  3. 完成后校验完整性:返回对象前,检查所有必填属性是否都已处理,未处理的直接抛出异常。

修改后的自定义转换器代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace JsonContractsTest
{
    public class TestClassConverter : JsonConverterFactory
    {
        public override bool CanConvert(Type typeToConvert)
        {
            return typeToConvert == typeof(TestClass);
        }

        public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
        {
            return new TestClassConverterInner(options);
        }

        private class TestClassConverterInner : JsonConverter<TestClass>
        {
            private JsonConverter<int> int32Converter { get; }
            private HashSet<string> requiredPropertyNames { get; }

            public TestClassConverterInner(JsonSerializerOptions options)
            {
                this.int32Converter = (JsonConverter<int>)options.GetConverter(typeof(int));
                // 提取TestClass中标记[JsonRequired]的属性名(忽略大小写)
                this.requiredPropertyNames = typeof(TestClass)
                    .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                    .Where(p => p.GetCustomAttribute<JsonRequiredAttribute>() != null)
                    .Select(p => p.Name)
                    .ToHashSet(StringComparer.OrdinalIgnoreCase);
            }

            public override TestClass? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            {
                if (reader.TokenType != JsonTokenType.StartObject)
                    throw new JsonException();

                TestClass obj = new TestClass();
                HashSet<string> processedRequiredProperties = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

                while (reader.Read())
                {
                    if (reader.TokenType == JsonTokenType.EndObject)
                    {
                        // 校验必填属性是否全部处理
                        var missingProperties = requiredPropertyNames.Except(processedRequiredProperties);
                        if (missingProperties.Any())
                        {
                            throw new JsonException($"缺少必填属性: {string.Join(", ", missingProperties)}");
                        }
                        return obj;
                    }

                    if (reader.TokenType != JsonTokenType.PropertyName)
                        throw new JsonException();

                    string? propertyName = reader.GetString();

                    reader.Read();
                    if (StringComparer.OrdinalIgnoreCase.Equals(nameof(TestClass.Value), propertyName))
                    {
                        obj.Value = this.int32Converter.Read(ref reader, typeof(int), options);
                        // 标记该必填属性已处理
                        if (requiredPropertyNames.Contains(propertyName))
                        {
                            processedRequiredProperties.Add(propertyName);
                        }
                    }
                }

                throw new JsonException();
            }

            public override void Write(Utf8JsonWriter writer, TestClass value, JsonSerializerOptions options)
            {
                throw new NotImplementedException();
            }
        }
    }
}

测试验证

启用自定义转换器后,运行你的测试代码:

JsonSerializerOptions options = new JsonSerializerOptions()
{
    Converters =
    {
        new TestClassConverter(),
    },
    PropertyNameCaseInsensitive = true,
};

此时反序列化缺少Value属性的JSON字符串,会抛出JsonException提示缺少必填属性,与默认转换器行为一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 14:41:22