如何在ASP.NET Core控制器ModelState中获取自定义ValidationResult
解决方案
1. 定义自定义ValidationResult子类
先创建包含自定义属性的CustomValidationResult,继承自框架的ValidationResult:
public class CustomValidationResult : ValidationResult { // 自定义属性,比如业务错误码 public string CustomErrorCode { get; } // 匹配基类构造函数,同时初始化自定义属性 public CustomValidationResult(string errorMessage, string customErrorCode, IEnumerable<string> memberNames) : base(errorMessage, memberNames) { CustomErrorCode = customErrorCode; } }
2. 实现自定义Mandatory属性
继承RequiredAttribute并重写IsValid方法,返回CustomValidationResult,同时将结果存入验证上下文的Items集合(方便控制器后续提取):
public class MandatoryAttribute : RequiredAttribute { // 可配置的自定义错误码 public string CustomErrorCode { get; set; } = "FIELD_MANDATORY"; protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var baseResult = base.IsValid(value, validationContext); if (baseResult != ValidationResult.Success) { var customResult = new CustomValidationResult( ErrorMessage ?? "此字段为必填项", CustomErrorCode, baseResult.MemberNames ); // 将自定义结果存入ValidationContext的Items if (!validationContext.Items.ContainsKey(nameof(CustomValidationResult))) { validationContext.Items[nameof(CustomValidationResult)] = new List<CustomValidationResult>(); } ((List<CustomValidationResult>)validationContext.Items[nameof(CustomValidationResult)]).Add(customResult); return customResult; } return ValidationResult.Success; } }
3. 控制器中同步自定义结果到ModelState
在Action中手动执行模型验证,获取完整的自定义结果后同步到ModelState:
public class FormController : Controller { [HttpPost] public IActionResult Submit(FormModel model) { // 初始化验证上下文和自定义结果集合 var validationContext = new ValidationContext(model); var customResults = new List<CustomValidationResult>(); validationContext.Items[nameof(CustomValidationResult)] = customResults; // 执行全属性验证 bool isValid = Validator.TryValidateObject( model, validationContext, null, validateAllProperties: true ); // 同步自定义结果到ModelState foreach (var result in customResults) { foreach (var memberName in result.MemberNames) { // 生成带错误码的消息 var fullErrorMessage = $"{result.ErrorMessage} [错误码: {result.CustomErrorCode}]"; // 更新ModelState if (ModelState.ContainsKey(memberName)) { ModelState[memberName].Errors.Clear(); ModelState[memberName].Errors.Add(fullErrorMessage); } else { ModelState.AddModelError(memberName, fullErrorMessage); } // 可选:直接将CustomValidationResult实例存入ModelState元数据 ModelState[memberName].Metadata.AdditionalValues["CustomResult"] = result; } } if (!isValid) { return BadRequest(ModelState); } // 业务逻辑处理 return Ok("提交成功"); } }
替代方案:编码自定义信息到错误消息
如果不想手动执行验证,可将自定义属性拼接进错误消息,在控制器中解析:
修改MandatoryAttribute的IsValid方法
protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var baseResult = base.IsValid(value, validationContext); if (baseResult != ValidationResult.Success) { // 用分隔符拼接错误消息和错误码 var encodedMsg = $"{ErrorMessage ?? "此字段为必填项"}|{CustomErrorCode}"; return new ValidationResult(encodedMsg, baseResult.MemberNames); } return ValidationResult.Success; }
控制器中解析错误消息
[HttpPost] public IActionResult Submit(FormModel model) { if (!ModelState.IsValid) { foreach (var key in ModelState.Keys) { foreach (var error in ModelState[key].Errors) { var parts = error.ErrorMessage.Split('|'); if (parts.Length == 2) { string originalMsg = parts[0]; string errorCode = parts[1]; // 这里可基于错误码做日志、多语言映射等操作 } } } return BadRequest(ModelState); } return Ok("提交成功"); }
关键说明
- ASP.NET Core默认模型验证会将
ValidationResult转换为ModelError,仅保留错误消息和成员名称,导致自定义属性丢失。 - 手动执行验证+
ValidationContext.Items传递的方式,能完整保留自定义结果的所有属性,是最可靠的方案。 - 编码错误消息的方式更简洁,但可读性和扩展性较差,适合简单场景。
内容的提问来源于stack exchange,提问作者Tarak Venkat
相关产品推荐
相关产品推荐

