Как использовать аннотации данных для условной проверки на модели?
Например, предположим, у нас есть следующая модель (Person и Senior):
public class Person
{
[Required(ErrorMessage = "*")]
public string Name
{
get;
set;
}
public bool IsSenior
{
get;
set;
}
public Senior Senior
{
get;
set;
}
}
public class Senior
{
[Required(ErrorMessage = "*")]//this should be conditional validation, based on the "IsSenior" value
public string Description
{
get;
set;
}
}
И следующее view:
<%= Html.EditorFor(m => m.Name)%>
<%= Html.ValidationMessageFor(m => m.Name)%>
<%= Html.CheckBoxFor(m => m.IsSenior)%>
<%= Html.ValidationMessageFor(m => m.IsSenior)%>
<%= Html.CheckBoxFor(m => m.Senior.Description)%>
<%= Html.ValidationMessageFor(m => m.Senior.Description)%>
Я хотел бы быть полем условного обязательного свойства "Senior.Description", основанным на выборе свойства IsSenior (true -> обязательный). Как реализовать условную валидацию в ASP.NET MVC 2 с аннотациями данных?
Я решил эту проблему путем работы со словарем "ModelState", который содержится в контроллере. Словарь ModelState включает в себя все члены, которые должны быть проверены.
Вот решение:
Если вам нужно реализовать условную валидацию на основе некоторого поля (например, если A=true, то B обязательно), сохраняя при этом сообщения об ошибках на уровне свойств (это не относится к пользовательским валидаторам на уровне объектов), вы можете добиться этого, обрабатывая "ModelState", просто удаляя из него ненужные валидации.
...В некотором классе...
public bool PropertyThatRequiredAnotherFieldToBeFilled
{
get;
set;
}
[Required(ErrorMessage = "*")]
public string DepentedProperty
{
get;
set;
}
...класс продолжается...
...В некотором действии контроллера ...
if (!PropertyThatRequiredAnotherFieldToBeFilled)
{
this.ModelState.Remove("DepentedProperty");
}
...
Этим мы добиваемся условной валидации, оставляя все остальное без изменений.
UPDATE:
Это моя окончательная реализация: Я использовал интерфейс на модели и атрибут действия, который проверяет модель, реализующую указанный интерфейс. Интерфейс предписывает метод Validate(ModelStateDictionary modelState). Атрибут action просто вызывает Validate(modelState) на IValidatorSomething.
Я не хотел усложнять этот ответ, поэтому я не упомянул финальные детали реализации (которые, в конце концов, имеют значение в производственном коде).
Вам необходимо пройти проверку на уровне Person, а не на уровне Senior, или Senior должен иметь ссылку на своего родительского Person. Мне кажется, что вам нужен механизм самопроверки, который определяет валидацию на человеке, а не на одном из его свойств. Я не уверен, но я не думаю, что DataAnnotations поддерживает это из коробки. Что вы можете сделать, создав свой собственный Атрибут
, производный от ValidationAttribute
, который можно оформить на уровне класса, а затем создать собственный валидатор, который также позволяет запускать эти валидаторы уровня класса.
Я знаю, что Validation Application Block сразу поддерживает самопроверку, но VAB требует довольно крутого обучения. Тем не менее, вот пример использования VAB:
[HasSelfValidation]
public class Person
{
public string Name { get; set; }
public bool IsSenior { get; set; }
public Senior Senior { get; set; }
[SelfValidation]
public void ValidateRange(ValidationResults results)
{
if (this.IsSenior && this.Senior != null &&
string.IsNullOrEmpty(this.Senior.Description))
{
results.AddResult(new ValidationResult(
"A senior description is required",
this, "", "", null));
}
}
}
Вы можете отключить валидаторы условно, удалив ошибки из ModelState:
ModelState["DependentProperty"].Errors.Clear();