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

自定义RangedIf验证属性无法在表单输入框下方显示错误提示

问题

我有一个可正常工作的自定义RequiredIf验证属性,之后需要实现RangedIf验证——当另一个属性为特定值时,当前属性必须在指定范围内。该验证功能可以正常生效,但错误提示不会显示在对应输入框下方。我猜测这是由于使用了return new ValidationResult导致的,想知道有没有遗漏的方法可以让自定义属性抛出的错误关联到对应的输入框?

RangedIf的定义规则:要检查的目标属性名称、触发验证的目标属性值、范围最小值和最大值。

实体类代码:

public string IsMonetized { get; set; } 

// [RequiredIf("IsMonetized", "Yes", "Please Enter a Value")]
// [Range(1, double.MaxValue, ErrorMessage = "Please Enter an Amount greater than 0")]
[RangedIf("IsMonetized", "Yes", 1, 200)]
public double MaxAmount { get; set; }

//[Range(1, 200, ErrorMessage = "Please Enter an Amount greater than 0")]
[RangedIf("IsMonetized", "Yes", 1, 200)]
public double? AnnualAmount { get; set; }

RangedIfAttribute类实现代码:

public class RangedIfAttribute : RequiredAttribute
{
    private String PropertyName { get; set; }
    private Object DesiredValue { get; set; }
    private double max { get; set; }
    private double min { get; set; }

    public RangedIfAttribute(String propertyName, Object desiredvalue, double Min, double Max)
    {
        PropertyName = propertyName;
        DesiredValue = desiredvalue;
        min = Min;
        max = Max;
    }

    public RangedIfAttribute(String propertyName, Object desiredvalue, double Min, double Max, String Errormessage)
    {
        PropertyName = propertyName;
        DesiredValue = desiredvalue;
        ErrorMessage = Errormessage;
        min = Min;
        max = Max;
    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        Object instance = context.ObjectInstance;
        Type type = instance.GetType();
        Object proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);

        try
        {
            if (proprtyvalue == null)
            {
                if (DesiredValue == null)
                {
                    if (min <= (double)value && (double)value <= max)
                    {
                        return base.IsValid(value, context); // Null was intended , and value in range - Valid
                    }
                }
            }
            else if (proprtyvalue.ToString().Equals(DesiredValue))
            {
                if (min <= (double)value && (double)value <= max)
                {
                    return base.IsValid(value, context); // desired = property value, and value in range - Valid
                }
            }

            // This should submit Not Valid
            return new ValidationResult(this.FormatErrorMessage(context.DisplayName));
        }
        catch
        {
            // this should submit not valid - the required item is null
            return new ValidationResult($"Value must be within the range of {min} and {max}");
        }
    }
}

目前两个输入框都不会即时显示错误标记,但底部的验证汇总中会显示错误信息:

  • The MaxAmount field is required.(MaxAmount字段不符合验证逻辑时显示)
  • Value must be within the range of 1 and 200(AnnualAmount为null触发catch时显示)

再次说明:该验证可阻止表单提交,但没有任何提示指明哪个输入框验证失败(正常验证失败时输入框会高亮红色)。

解决方案

问题核心在于两点:

  1. 继承RequiredAttribute引入了不必要的验证逻辑,干扰了错误绑定规则;
  2. 返回ValidationResult时未指定当前属性的成员名称,前端无法识别错误归属。

修复步骤

1. 更换基类

将RangedIfAttribute的基类从RequiredAttribute改为ValidationAttribute,避免继承与范围验证无关的逻辑。

2. 指定错误关联的成员名称

返回ValidationResult时,传入当前属性的名称(通过context.MemberName获取),让验证框架明确错误属于哪个字段。

修改后的完整代码

public class RangedIfAttribute : ValidationAttribute
{
    private string PropertyName { get; set; }
    private object DesiredValue { get; set; }
    private double Max { get; set; }
    private double Min { get; set; }

    public RangedIfAttribute(string propertyName, object desiredValue, double min, double max)
    {
        PropertyName = propertyName;
        DesiredValue = desiredValue;
        Min = min;
        Max = max;
    }

    public RangedIfAttribute(string propertyName, object desiredValue, double min, double max, string errorMessage)
    {
        PropertyName = propertyName;
        DesiredValue = desiredValue;
        ErrorMessage = errorMessage;
        Min = min;
        Max = max;
    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        var instance = context.ObjectInstance;
        var type = instance.GetType();
        var propertyValue = type.GetProperty(PropertyName)?.GetValue(instance, null);

        try
        {
            // 判断是否需要触发范围验证
            bool shouldValidate = false;
            if (propertyValue == null && DesiredValue == null)
            {
                shouldValidate = true;
            }
            else if (propertyValue?.ToString().Equals(DesiredValue) == true)
            {
                shouldValidate = true;
            }

            if (!shouldValidate)
            {
                return ValidationResult.Success;
            }

            // 空值判断(针对可空类型)
            if (value == null)
            {
                return new ValidationResult(FormatErrorMessage(context.DisplayName), new[] { context.MemberName });
            }

            // 类型转换与范围检查
            if (double.TryParse(value.ToString(), out var doubleValue))
            {
                if (doubleValue >= Min && doubleValue <= Max)
                {
                    return ValidationResult.Success;
                }
            }

            // 返回范围错误,指定成员名称
            return new ValidationResult(FormatErrorMessage(context.DisplayName), new[] { context.MemberName });
        }
        catch
        {
            // 异常时返回错误,指定成员名称
            return new ValidationResult($"Value must be within the range of {Min} and {Max}", new[] { context.MemberName });
        }
    }
}

额外优化说明

  • 使用ValidationResult.Success明确表示验证通过,逻辑更清晰;
  • 增加了空值和类型转换的安全判断,避免强制转换引发的异常;
  • 统一通过new[] { context.MemberName }指定错误归属的属性,确保前端能将错误提示绑定到对应输入框。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 11:25:37