Я читал на каком-то посту, но не могу найти его сейчас, когда в MVC 3 не было необходимости создавать Validator, а только атрибут. Это правда? Я действительно говорю, что я сбиваю с толку, что атрибут имеет IClientValidatable. Итак, что делает класс DataAnnotationsModelValidator, если аннотация содержит имя клиента script (IClientValidatable) и возможность проверки (ValidationAttribute IsValid)?
Было бы очень приятно, если бы мне не пришлось регистрировать атрибут с помощью Validator в глобальном. Это можно сделать? Я читал плохие советы?
EDIT: Интересно, что я просто протестировал его, исключив валидатор, поместив всю логику в 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;
}
}
Есть ли проблема с последним битом кода, заменяющим весь другой код? Почему я должен хранить класс валидатора?