.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
相关产品推荐
相关产品推荐

