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

.NET Core如何实现带错误码的自定义数据注解验证功能

.NET Core 自定义验证特性绑定专属错误码实现方案

核心实现思路

原生System.ComponentModel.DataAnnotations.ValidationAttribute配合框架自带的ValidationResult类型本身就支持扩展自定义错误字段,不需要引入第三方组件,直接扩展基类即可实现错误消息和错误码的绑定。


步骤1:定义带错误码能力的验证特性基类

所有自定义验证特性继承这个基类,自动获得错误码绑定能力,不需要每个特性重复写错误码处理逻辑:

using System.ComponentModel.DataAnnotations;

public abstract class ErrorCodeValidationAttribute : ValidationAttribute
{
    /// <summary>
    /// 验证错误对应的业务错误码,支持传入字符串、枚举、数字类型
    /// </summary>
    public object ErrorCode { get; set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var errorMessage = GetValidateErrorMsg(value, validationContext);
        if (string.IsNullOrWhiteSpace(errorMessage))
        {
            return ValidationResult.Success;
        }

        var validationResult = new ValidationResult(errorMessage, new[] { validationContext.MemberName })
        {
            // 直接给框架自带的ValidationResult赋值ErrorCode
            ErrorCode = ErrorCode?.ToString()
        };
        return validationResult;
    }

    /// <summary>
    /// 子类重写该方法实现具体验证逻辑,验证通过返回null,不通过返回错误消息即可
    /// </summary>
    protected abstract string GetValidateErrorMsg(object value, ValidationContext validationContext);
}

如果你用的是低于2.0版本的.NET Core,ValidationResult没有自带ErrorCode属性,可以把错误码存在validationResult.Data["ErrorCode"]字典中,读取时对应取值即可。


步骤2:编写具体业务验证特性

以手机号格式验证为例,只需要关注验证逻辑本身,不需要处理错误码绑定:

using System.Text.RegularExpressions;

public class MobilePhoneAttribute : ErrorCodeValidationAttribute
{
    private static readonly Regex _mobileRegex = new Regex(@"^1[3-9]\d{9}$", RegexOptions.Compiled);

    protected override string GetValidateErrorMsg(object value, ValidationContext validationContext)
    {
        if (value is not string input || string.IsNullOrWhiteSpace(input))
        {
            return ErrorMessage ?? "手机号不能为空";
        }
        return _mobileRegex.IsMatch(input) ? null : ErrorMessage ?? "请输入有效的11位手机号";
    }
}

步骤3:在模型上使用并指定错误码

推荐用枚举统一管理全局业务错误码,避免硬编码字符串导致的混乱:

// 全局业务错误码枚举
public enum BizErrorCode
{
    InvalidMobile = 10001,
    PasswordTooShort = 10002,
    EmailFormatInvalid = 10003
}

// DTO模型上使用验证特性
public class UserRegisterDto
{
    [MobilePhone(ErrorCode = BizErrorCode.InvalidMobile, ErrorMessage = "请输入有效的11位中国大陆手机号")]
    public string Mobile { get; set; }

    [MinLength(8, ErrorCode = BizErrorCode.PasswordTooShort, ErrorMessage = "密码长度不能少于8位")]
    public string Password { get; set; }
}

框架原生自带的验证特性(比如MinLength、Required、RegularExpression)本身也支持直接给ErrorCode属性赋值,不需要额外改造。


步骤4:全局校验拦截时读取错误码返回

在全局模型校验拦截器或者过滤器中,直接从模型状态错误中读取绑定的错误码,统一返回给前端:

public class GlobalValidateFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.ModelState.IsValid) return;
        
        var errorList = new List<object>();
        foreach (var modelStateEntry in context.ModelState.Values)
        {
            foreach (var modelError in modelStateEntry.Errors)
            {
                var errorCode = "SYSTEM_VALIDATE_ERROR";
                if (modelError.Exception is ValidationException validateEx)
                {
                    errorCode = validateEx.ValidationResult?.ErrorCode?.ToString() ?? errorCode;
                }
                errorList.Add(new
                {
                    Code = errorCode,
                    Msg = modelError.ErrorMessage
                });
            }
        }

        context.Result = new JsonResult(new
        {
            Success = false,
            Errors = errorList
        })
        {
            StatusCode = 400
        };
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
    }
}

把这个过滤器注册到MVC全局过滤器配置中,所有接口的验证错误都会自动带上绑定的专属错误码返回。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 02:33:08