使用自定义System.Text.Json转换器时如何强制必填属性
自定义System.Text.Json转换器时如何强制[JsonRequired]校验?
当使用System.Text.Json默认转换器时,标记[JsonRequired]的属性若在JSON中缺失,反序列化会正常抛出JsonException。但自定义JsonConverter后,默认的必填校验逻辑不会自动执行,导致缺失必填属性时仍能成功反序列化对象。以下是针对你的代码的解决办法:
解决步骤
- 提取必填属性元数据:在转换器初始化阶段,获取目标类型中标记了
[JsonRequired]的属性名称。 - 跟踪已处理的必填属性:反序列化过程中,记录哪些必填属性已被读取并赋值。
- 完成后校验完整性:返回对象前,检查所有必填属性是否都已处理,未处理的直接抛出异常。
修改后的自定义转换器代码
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
相关产品推荐
相关产品推荐

