ASP.NET MVC Условная проверка

Как использовать annotations данных для выполнения условной проверки на модели?

Например, скажем, у нас есть следующая модель (Person and 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; } } 

И следующее представление:

  m.Name)%>  m.Name)%>  m.IsSenior)%>  m.IsSenior)%>  m.Senior.Description)%>  m.Senior.Description)%> 

Я хотел бы быть обязательным полем «Senior.Description» условным обязательным полем, основанным на выборе свойства «IsSenior» (true -> required). Как реализовать условную проверку в ASP.NET MVC 2 с аннотациями данных?

есть намного лучший способ добавить правила условной валидации в MVC3. Пусть ваша модель наследует объект IValidatableObject и реализует метод Validate:

 public class Person : IValidatableObject { public string Name { get; set; } public bool IsSenior { get; set; } public Senior Senior { get; set; } public IEnumerable Validate(ValidationContext validationContext) { if (IsSenior && string.IsNullOrEmpty(Senior.Description)) yield return new ValidationResult("Description must be supplied."); } } 

подробнее см. на http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx

Я решил это, обратившись к словарю «ModelState» , который содержится в controllerе. Словарь ModelState включает в себя все члены, которые должны быть проверены.

Вот решение:

Если вам нужно выполнить условную проверку на основе некоторого поля (например, если A = true, тогда требуется B), при этом поддерживается сообщение об ошибках уровня уровня собственности (это неверно для пользовательских валидаторов, находящихся на уровне объекта), вы можете достичь этого путем обработки «ModelState», просто удалив из него нежелательные проверки.

… В каком-то classе …

 public bool PropertyThatRequiredAnotherFieldToBeFilled { get; set; } [Required(ErrorMessage = "*")] public string DepentedProperty { get; set; } 

… class продолжается …

… В некоторых действиях controllerа …

 if (!PropertyThatRequiredAnotherFieldToBeFilled) { this.ModelState.Remove("DepentedProperty"); } 

При этом мы получаем условную валидацию, оставляя все остальное одинаковым.


ОБНОВИТЬ:

Это моя последняя реализация: я использовал интерфейс для модели и атрибут действия, который проверяет модель, которая реализует указанный интерфейс. Интерфейс предписывает метод Validate (ModelStateDictionary modelState). Атрибут action просто вызывает Validate (modelState) в файле IValidatorSomething.

Я не хотел усложнять этот ответ, поэтому я не упомянул о последних деталях реализации (которые, в конце концов, имеют значение в производственном коде).

Вчера у меня была такая же проблема, но я сделал это очень чистым способом, который работает как на стороне клиента, так и на стороне сервера.

Условие: исходя из значения другого свойства в модели, вы хотите сделать еще одно свойство. Вот код

 public class RequiredIfAttribute : RequiredAttribute { private String PropertyName { get; set; } private Object DesiredValue { get; set; } public RequiredIfAttribute(String propertyName, Object desiredvalue) { PropertyName = propertyName; DesiredValue = desiredvalue; } protected override ValidationResult IsValid(object value, ValidationContext context) { Object instance = context.ObjectInstance; Type type = instance.GetType(); Object proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null); if (proprtyvalue.ToString() == DesiredValue.ToString()) { ValidationResult result = base.IsValid(value, context); return result; } return ValidationResult.Success; } } 

Здесь PropertyName – это свойство, на которое вы хотите выполнить свое условие. DesiredValue – это конкретное значение свойства PropertyName (property), для которого ваше другое свойство должно быть подтверждено для требуемого

Скажем, у вас есть следующее

 public class User { public UserType UserType { get; set; } [RequiredIf("UserType", UserType.Admin, ErrorMessageResourceName = "PasswordRequired", ErrorMessageResourceType = typeof(ResourceString))] public string Password { get; set; } } 

Наконец, но не в последнюю очередь, зарегистрируйте адаптер для вашего атрибута, чтобы он мог выполнять проверку на стороне клиента (я поместил его в global.asax, Application_Start)

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

Я использую этот удивительный nuget, который делает динамические annotations ExpressiveAnnotations

Вы можете проверить любую логику, о которой вы можете мечтать:

 public string Email { get; set; } public string Phone { get; set; } [RequiredIf("Email != null")] [RequiredIf("Phone != null")] [AssertThat("AgreeToContact == true")] public bool? AgreeToContact { get; set; } 

Вы можете отключить валидаторы условно, удалив ошибки из ModelState:

 ModelState["DependentProperty"].Errors.Clear(); 

Спасибо Мерритту 🙂

Я только что обновил это до MVC 3 на случай, если кто-нибудь найдет его полезным; http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx

Саймон

В настоящее время существует фреймворк, который делает эту условную проверку (среди других полезных проверок annotations данных) из коробки: http://foolproof.codeplex.com/

В частности, посмотрите на валидатор [RequiredIfTrue («IsSenior»)]. Вы помещаете это непосредственно в свойство, которое хотите проверить, так что вы получаете желаемое поведение ошибки проверки, связанной с свойством «Старший».

Он доступен как пакет NuGet.

Вам необходимо пройти проверку на уровне Лица, а не на старшем уровне, или Старший должен иметь ссылку на своего родителя. Мне кажется, что вам нужен механизм проверки подлинности, который определяет валидацию для Лица, а не одного из его свойств. Я не уверен, но я не думаю, что DataAnnotations поддерживает это из коробки. Что вы можете сделать, создайте свой собственный Attribute , полученный из ValidationAttribute который может быть оформлен на уровне classа, а затем создайте специальный валидатор, который также позволяет запускать эти валидаторы на уровне classов.

Я знаю, что блок Application Validation поддерживает самооценку из коробки, но 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)); } } } 

Проверьте этого парня:

http://blogs.msdn.com/b/simonince/archive/2010/06/04/conditional-validation-in-mvc.aspx

Сейчас я работаю над его примером.

У меня была такая же проблема, мне нужна модификация атрибута [Обязательный] – введите поле, требуемое в зависимости от http-запроса. Решение было похоже на ответ Дэна Хунэса, но его решение не сработало (см. Комментарии). Я не использую ненавязчивую проверку, просто MicrosoftMvcValidation.js из коробки. Вот. Внедрите свой собственный атрибут:

 public class RequiredIfAttribute : RequiredAttribute { public RequiredIfAttribute(/*You can put here pararmeters if You need, as seen in other answers of this topic*/) { } protected override ValidationResult IsValid(object value, ValidationContext context) { //You can put your logic here return ValidationResult.Success;//I don't need its server-side so it always valid on server but you can do what you need } } 

Затем вам нужно реализовать свой пользовательский поставщик, чтобы использовать его в качестве адаптера в вашем global.asax

 public class RequreIfValidator : DataAnnotationsModelValidator  { ControllerContext ccontext; public RequreIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute) : base(metadata, context, attribute) { ccontext = context;// I need only http request } //override it for custom client-side validation public override IEnumerable GetClientValidationRules() { //here you can customize it as you want ModelClientValidationRule rule = new ModelClientValidationRule() { ErrorMessage = ErrorMessage, //and here is what i need on client side - if you want to make field required on client side just make ValidationType "required" ValidationType =(ccontext.HttpContext.Request["extOperation"] == "2") ? "required" : "none"; }; return new ModelClientValidationRule[] { rule }; } } 

И измените свой global.asax на строку

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

и здесь

 [RequiredIf] public string NomenclatureId { get; set; } 

Главное для меня в том, что мне не нужно кодировать пользовательский валидатор клиента, как в случае ненавязчивой проверки. он работает так же, как [Требуется], но только в тех случаях, которые вы хотите.

Типичное использование для условного удаления ошибки из состояния модели:

  1. Сделать условную первую часть действия controllerа
  2. Выполните логику для удаления ошибки от ModelState
  3. Остальная часть существующей логики (обычно проверка состояния модели, затем все остальное)

Пример:

 public ActionResult MyAction(MyViewModel vm) { // perform conditional test // if true, then remove from ModelState (eg ModelState.Remove("MyKey") // Do typical model state validation, inside following if: // if (!ModelState.IsValid) // Do rest of logic (eg fetching, saving 

В вашем примере сохраните все как есть и добавьте логику, предложенную в действие вашего controllerа. Я предполагаю, что ваш ViewModel, переданный в действие controllerа, имеет объекты Person и Senior Person с данными, заполненными ими из пользовательского интерфейса.

Я использую MVC 5, но вы можете попробовать что-то вроде этого:

 public DateTime JobStart { get; set; } [AssertThat("StartDate >= JobStart", ErrorMessage = "Time Manager may not begin before job start date")] [DisplayName("Start Date")] [Required] public DateTime? StartDate { get; set; } 

В вашем случае вы скажете что-то вроде «IsSenior == true». Затем вам просто нужно проверить валидацию в своем посту.

Interesting Posts
Давайте будем гением компьютера.