对需要其他属性值的属性进行验证

本文关键字:属性 验证 其他 | 更新日期: 2023-09-27 18:17:03

所以我已经检查了这个答案asp.net MVC 4动态验证的属性取决于另一个属性的当前值,它不包括我的问题。

我使用服务器端验证。我有一个要求……

只有在指定了其他属性时才需要该值

MVC绑定每个属性,并在绑定时调用该属性上的每个验证器。如果我依赖于多个属性,当我检查validationContext.ObjectInstance.[MY_DEPENDENT_PROPERTY]时,有可能那些依赖的属性还没有被绑定。

我需要的是一个验证属性,在绑定之后验证 -如果存在的话。


所以这里有一个简单的例子来解释我的情况(不打算被执行,因为它很可能会很好,因为这个问题与绑定顺序有关)

我的模型
public class Address
{
    [Required]
    public string ResidentialAddress { get; set; }
    public bool PostalIsTheSameAsResidential { get; set; }
    // will only be required if PostalIsTheSameAsResidential is false.
    // see the static method below and RequiredIfAttribute
    [RequiredIf(typeof(Address), nameof(PostalRequiredIfNotSameAsResidential)]
    public string PostalAddress { get; set; }
    public static bool PostalRequiredIfNotSameAsResidential(Address model)
    {
        return !model.PostalIsTheSameAsResidential;
    }
}

我的验证器

本质上,这里发生的事情是调用模型上的静态方法来查看它是否应该验证。

public sealed class RequiredIfAttribute : RequiredAttribute
{
    private readonly MethodInfo _validationMethod;
    public override bool RequiresValidationContext => true;
    public RequiredIfAttribute(Type type, string methodName)
    {
        this._validationMethod = type.GetMethod(methodName);
        if (this._validationMethod == null)
        {
            throw new MethodAccessException($"The validation method '{methodName}' does not exist on type '{type}");
        }
    }
    public override bool IsValid(object value)
    {
        throw new NotSupportedException();
    }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        ValidationResult result = ValidationResult.Success;
        var parameters = this._validationMethod.GetParameters();
        var returnType = this._validationMethod.ReturnType;
        if (returnType == typeof(bool) && parameters.Length == 1 && parameters[0].ParameterType == validationContext.ObjectType)
        {
            if ((bool)_validationMethod.Invoke(null, new object[] { validationContext.ObjectInstance }))
            {
                if (!base.IsValid(value))
                {
                    string[] memberNames;
                    if (validationContext.MemberName == null)
                    {
                        memberNames = null;
                    }
                    else
                    {
                        memberNames = new string[1];
                        memberNames[0] = validationContext.MemberName;
                    }
                    result = new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName), memberNames);
                }
            }
            return result;
        }
        var expectedFuncType = typeof(Func<,>).MakeGenericType(validationContext.ObjectType, typeof(bool));
        throw new MethodAccessException($"The validation method '{this._validationMethod}' does not have the correct definition. Expected '{expectedFuncType}'");
    }
}

对需要其他属性值的属性进行验证

所以这个问题,我有是我从RequiredAttribute继承。MVC内部对这个属性的处理方式与其他属性不同。

当模型绑定器循环遍历属性时,它获得RequiredAttribute s并同时执行它们…

// System.Web.Mvc.DefaultModelBinder.SetProperty
....
    ModelValidator modelValidator = (from v in ModelValidatorProviders.Providers.GetValidators(modelMetadata, controllerContext)
        where v.IsRequired
        select v).FirstOrDefault<ModelValidator>();
        if (modelValidator != null)
        {
            foreach (ModelValidationResult current in modelValidator.Validate(bindingContext.Model))
            {
                bindingContext.ModelState.AddModelError(key, current.Message);
            }
        }
....

v.IsRequired实际上解析为一行,该行测试当前属性是否为RequiredAttribute,并将在当前不完整的模型状态下验证它。

通过继承ValidationAttribute,它在模型建立后运行验证并解决了我的问题。


感谢@StephenMuecke给我的提示