使用DataAnnotationsModelValidatorProvider.RegisterAdapter的MVC 2与MVC 3自定义验证属性

时间:2011-06-27 15:52:30

标签: asp.net-mvc asp.net-mvc-3 validation asp.net-mvc-2

我读过一些帖子,但现在无法找到它,在MVC 3中并不是真的需要创建一个Validator,只有Attribute。这是真的?我确实说我发现该属性上有IClientValidatable令人困惑。那么,如果注释具有客户端脚本名称(IClientValidatable),那么DataAnnotationsModelValidator类会做什么,以及验证的能力(ValidationAttribute IsValid)?

如果我不必在全局中使用Validator注册Attribute,那将是非常好的。可以这样做吗?我读过一些不好的建议吗?

编辑:有趣的是我只是通过排除验证器来测试它,将所有逻辑放在IsValid中并且它工作得很好。我想唯一可能缺少的是控制器上下文,但我不确定它在验证中是否有用。如果我需要服务,IsValid有ValidationContext,它有ServiceContainer。我没有在这里找到任何真正的劣势吗?

编辑2: 我将从此示例中的验证器开始:http://blogs.msdn.com/b/simonince/archive/2010/06/04/conditional-validation-in-mvc.aspx

属性:

public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
{
    private RequiredAttribute innerAttribute = new RequiredAttribute();
    public string DependentProperty { get; set; }
    public object TargetValue { get; set; }

    public RequiredIfAttribute(string dependentProperty, object targetValue)
    {
        this.DependentProperty = dependentProperty;
        this.TargetValue = targetValue;
    }

    public override bool IsValid(object value)
    {
        return innerAttribute.IsValid(value);
    }

    public System.Collections.Generic.IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        ModelClientValidationRule modelClientValidationRule = new ModelClientValidationRule()
        {
            ErrorMessage = FormatErrorMessage(metadata.DisplayName),
            ValidationType = "requiredifattribute"
        };
        modelClientValidationRule.ValidationParameters.Add("requiredifattribute", DependentProperty);
        yield return modelClientValidationRule;
    }
}

验证者:

public class RequiredIfValidator : DataAnnotationsModelValidator<RequiredIfAttribute>
{
    public RequiredIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute)
        : base(metadata, context, attribute)
    {
    }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        return base.GetClientValidationRules();
    }

    public override IEnumerable<ModelValidationResult> Validate(object container)
    {
        var field = Metadata.ContainerType.GetProperty(Attribute.DependentProperty);
        if (field != null)
        {
            var value = field.GetValue(container, null);
            if ((value == null && Attribute.TargetValue == null) ||
                (value.Equals(Attribute.TargetValue)))
            {
                if (!Attribute.IsValid(Metadata.Model))
                    yield return new ModelValidationResult { Message = ErrorMessage };
            }
        }
    }
}

使用上面的当前代码,我需要在Global.asax.cs文件中注册:

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute), typeof(RequiredIfValidator));

但如果我将所有内容都移到属性中,我就不必注册它:

public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
{
    private RequiredAttribute innerAttribute = new RequiredAttribute();
    public string DependentProperty { get; set; }
    public object TargetValue { get; set; }

    public RequiredIfAttribute(string dependentProperty, object targetValue)
    {
        this.DependentProperty = dependentProperty;
        this.TargetValue = targetValue;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var field = validationContext.ObjectInstance.GetType().GetProperty(DependentProperty);
        if (field != null)
        {
            var dependentValue = field.GetValue(validationContext.ObjectInstance, null);
            if ((dependentValue == null && TargetValue == null) ||
                (dependentValue.Equals(TargetValue)))
            {
                if (!innerAttribute.IsValid(value))
                    return new ValidationResult(ErrorMessage);
            }
        }
        return ValidationResult.Success;
    }

    public System.Collections.Generic.IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        ModelClientValidationRule modelClientValidationRule = new ModelClientValidationRule()
        {
            ErrorMessage = FormatErrorMessage(metadata.DisplayName),
            ValidationType = "requiredifattribute"
        };
        modelClientValidationRule.ValidationParameters.Add("requiredifattribute", DependentProperty);
        yield return modelClientValidationRule;
    }
}

最后一段代码替换所有其他代码是否有问题?为什么我会保留验证器类?

2 个答案:

答案 0 :(得分:10)

CrazyDart,

MVC3中添加了IClientValidatable接口。

您的第二个示例显示了此新界面的有效使用。你是正确的,它不需要注册,它将提供必要的客户端规则进行验证,以及进行必要的服务器端验证。

来吧,享受吧。

counsellorben

答案 1 :(得分:0)

当我使用CrazyDart的最后一个选项时,服务器端部分在MVC4中运行良好。

除了我无法使客户端验证工作。它从不检查客户端上的必填字段(尽管添加了一些标记)。

我还查看了Simon Ince的第二篇博文(第一篇是海报的灵感): http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx