使用特性为枚举类型模型属性返回自定义错误消息
问题
我的API请求体JSON会被解析为模型,模型包含多个枚举类型属性,示例属性代码如下:
public Enums.YesNo Indicator { get; set; }
我已在Program.cs中配置:
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
当JSON中未提供合法的Yes/No值时,我希望返回自定义错误消息“Invalid Indicator value”,但尝试使用[StringEnumValidation(typeof(Enums.YesNo), "Invalid Indicator value.")]和[EnumDataType(typeof(Enums.YesNo), ErrorMessage = "Invalid Indicator value.")]特性验证后,均未实现预期效果。
解决方案
默认的JsonStringEnumConverter解析失败时会直接抛出异常,不会触发数据注解验证,因此需要通过以下两种方式实现需求:
方法一:自定义JSON枚举转换器
实现带错误提示的自定义转换器,替换默认枚举转换器:
public class CustomStringEnumConverter : JsonStringEnumConverter { private readonly Type _enumType; private readonly string _errorMessage; public CustomStringEnumConverter(Type enumType, string errorMessage) { _enumType = enumType; _errorMessage = errorMessage; } public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { try { return base.Read(ref reader, typeToConvert, options); } catch (JsonException) { throw new ValidationException(_errorMessage); } } }
在模型属性上指定该转换器:
[JsonConverter(typeof(CustomStringEnumConverter), typeof(Enums.YesNo), "Invalid Indicator value")] public Enums.YesNo Indicator { get; set; }
注意:需移除Program.cs中原来的JsonStringEnumConverter全局配置,避免冲突。
方法二:全局异常过滤器捕获枚举解析错误
通过全局过滤器统一处理所有枚举解析失败的情况:
- 实现异常过滤器:
public class EnumValidationExceptionFilter : IExceptionFilter { public void OnException(ExceptionContext context) { if (context.Exception is JsonException jsonEx && jsonEx.Message.Contains("was not recognized as a valid enum")) { var propertyName = ExtractInvalidEnumProperty(jsonEx); var errorMessage = $"Invalid {propertyName} value"; context.Result = new BadRequestObjectResult(new ValidationProblemDetails { Errors = new Dictionary<string, string[]> { { propertyName, new[] { errorMessage } } } }); context.ExceptionHandled = true; } } private string ExtractInvalidEnumProperty(JsonException ex) { // 从错误消息中提取属性路径,示例错误消息格式:"The JSON value could not be converted to Enums.YesNo. Path: $.Indicator | LineNumber: 2 | BytePositionInLine: 18." var pathStart = ex.Message.IndexOf("Path: $.", StringComparison.Ordinal) + 7; var pathEnd = ex.Message.IndexOf(" | ", pathStart, StringComparison.Ordinal); return pathEnd > pathStart ? ex.Message.Substring(pathStart, pathEnd - pathStart) : "value"; } }
- 在Program.cs注册过滤器:
builder.Services.AddControllers(options => { options.Filters.Add<EnumValidationExceptionFilter>(); });
该方式无需修改模型属性,可全局处理所有枚举类型的解析错误,自动返回对应属性的自定义提示。
内容的提问来源于stack exchange,提问作者DRG
相关产品推荐
相关产品推荐

