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

EnumDataType特性自定义ErrorMessage失效,无效枚举值报错问题求助

问题描述

我在DTO中定义了如下代码:

[EnumDataType(typeof(Role), ErrorMessage = "The role must be one of; ...")]
public Role Role { get; set; }

我的Role枚举带有[JsonConverter(typeof(JsonStringEnumConverter))]特性。

调用接口时,若JSON中未提供role属性,能正常收到自定义错误信息The role must be one of; ...;但如果传入的role不是有效的Role枚举值,却不会返回这个自定义错误,而是得到如下报错:

"errors": [
  "input": [
    "The input field is required."
    ],
    "$.role": [
      "The JSON value could not be converted to Role. Path $.role | LineNumber: 3 | BytePosition: 16."
    ]
  ]
]

说明:上述的input指接口动作的参数名称。

我疑惑的是,为什么未传属性时自定义错误正常生效,传入无效枚举值时却不生效?我理解这个错误的含义(无法转换传入的值,推测是因为没有对应的枚举值),但如何让传入无效值时返回我自定义的错误信息?

原因

[EnumDataType]特性是在模型验证阶段起作用的,但JSON反序列化失败发生在模型绑定之前。当你传入无效枚举值时,JsonStringEnumConverter在反序列化环节就直接抛出了转换异常,根本没进入模型验证流程,所以自定义错误信息不会被触发。

而未传role属性时,因为枚举是值类型,反序列化会自动初始化它的默认值,之后模型验证会检查这个默认值是否属于Role的有效枚举范围,这时[EnumDataType]的错误信息就会生效。

解决方法

方法一:自定义JsonConverter

继承JsonStringEnumConverter,重写读取逻辑,遇到无效值时抛出带自定义错误的异常:

public class CustomStringEnumConverter : JsonStringEnumConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            return base.ReadJson(reader, objectType, existingValue, serializer);
        }
        catch (JsonException)
        {
            throw new JsonException("The role must be one of; ...");
        }
    }
}

然后把枚举上的特性替换成:

[JsonConverter(typeof(CustomStringEnumConverter))]
public enum Role { /* 枚举值 */ }

之后可以通过全局异常过滤器捕获这个自定义异常,返回对应的错误响应。

方法二:自定义验证属性+调整反序列化配置

如果不想修改JsonConverter,可以先配置反序列化时允许无效枚举值(避免提前抛异常),再用自定义验证属性检查值的有效性:

  1. 配置反序列化选项(以ASP.NET Core为例,在Program.cs/Startup.cs中):
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter
        {
            // 不允许整数形式的枚举值(如果不需要的话)
            AllowIntegerValues = false,
            // 遇到未知枚举值时返回默认值,这样反序列化不会失败
            UnknownEnumValueHandling = UnknownEnumValueHandling.Default
        });
    });
  1. 创建自定义验证属性:
public class ValidEnumAttribute : ValidationAttribute
{
    private readonly Type _enumType;

    public ValidEnumAttribute(Type enumType)
    {
        _enumType = enumType;
        ErrorMessage = "The role must be one of; ...";
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        // 检查值是否为有效枚举值
        if (!Enum.IsDefined(_enumType, value))
        {
            return new ValidationResult(ErrorMessage);
        }
        return ValidationResult.Success;
    }
}
  1. 在DTO属性上使用这个特性:
[ValidEnum(typeof(Role))]
public Role Role { get; set; }

这样反序列化不会因为无效值失败,进入模型验证阶段后,自定义属性会检查值的有效性并返回你设置的错误信息。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:30:42