.NET 3.1中Json序列化未定义枚举值不报错的优雅解决方法
.NET 3.1下枚举非法值的校验方案
针对.NET 3.1中枚举绑定非法值时自动设为默认值的问题,以下是几种更优雅的解决方式:
1. 自定义Json转换器(适配JSON请求体)
因为接口使用[FromBody]接收JSON数据,可给枚举类型添加自定义JsonConverter,在反序列化阶段校验值的合法性:
public class StrictEnumConverter<TEnum> : JsonConverter<TEnum> where TEnum : struct, Enum { public override TEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var valueStr = reader.GetString(); if (!Enum.TryParse<TEnum>(valueStr, ignoreCase: false, out var result) || !Enum.IsDefined(typeof(TEnum), result)) { throw new JsonException($"无效的枚举值:{valueStr},允许的值为:{string.Join(", ", Enum.GetNames(typeof(TEnum)))}"); } return result; } public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString()); } }
给枚举类添加特性指定转换器:
[JsonConverter(typeof(StrictEnumConverter<ChangeTime>))] public enum ChangeTime { Immediate, Later }
当传入非法值时,系统会抛出JsonException,自动返回400 Bad Request响应,无需手动处理。
2. 自定义验证属性
创建验证属性标记在枚举字段上,在模型验证阶段校验值的合法性:
public class ValidEnumValueAttribute : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (value == null) { return ValidationResult.Success; // 若不允许空值,可返回对应错误 } var enumType = value.GetType(); if (!Enum.IsDefined(enumType, value)) { return new ValidationResult($"值 {value} 不是有效的 {enumType.Name} 枚举值,允许的值为:{string.Join(", ", Enum.GetNames(enumType))}"); } return ValidationResult.Success; } }
在Request类的字段上添加该属性:
public class Request { [ValidEnumValue] public ChangeTime ChangeTime { get; set; } }
在接口中判断模型验证状态:
[HttpPost("test")] public async Task<ActionResult> Post([FromBody]Request request) { if (!ModelState.IsValid) { return BadRequest(ModelState); } // 后续业务逻辑 }
3. 全局配置严格枚举校验(适配所有枚举)
若希望所有枚举都启用严格校验,可在Startup.cs的ConfigureServices中全局配置Json序列化选项:
services.AddControllers() .AddJsonOptions(options => { // 遍历当前程序集所有枚举类型,添加严格转换器 foreach (var enumType in Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsEnum)) { var converterType = typeof(StrictEnumConverter<>).MakeGenericType(enumType); options.JsonSerializerOptions.Converters.Add((JsonConverter)Activator.CreateInstance(converterType)); } });
这样所有枚举都会自动应用严格校验,无需逐个添加特性。
以上方案均优于改为string手动校验的方式,性能损耗可忽略,同时能准确拦截非法枚举值并返回合适的错误响应。
内容的提问来源于stack exchange,提问作者user17603119
相关产品推荐
相关产品推荐

