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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 21:55:15