Как заставить MVC проверять объект IValidatableObject

Похоже, что когда MVC проверяет модель, которая сначала запускается через атрибуты DataAnnotation (например, требуемый или диапазон), и если кто-либо из них не работает, он пропускает метод Validate в моей модели IValidatableObject.

Есть ли способ запустить MVC и запустить этот метод, даже если другая проверка не удалась?

Вы можете вручную вызвать Validate (), передав новый экземпляр ValidationContext, например:

[HttpPost] public ActionResult Create(Model model) { if (!ModelState.IsValid) { var errors = model.Validate(new ValidationContext(model, null, null)); foreach (var error in errors) foreach (var memberName in error.MemberNames) ModelState.AddModelError(memberName, error.ErrorMessage); return View(post); } } 

Предостережение этого подхода заключается в том, что в тех случаях, когда ошибки на уровне свойств (DataAnnotation) отсутствуют, проверка будет выполняться дважды. Чтобы этого избежать, вы можете добавить свойство в свою модель, скажем, логическое значение Validated, которое вы установили в метод Validate (), когда оно выполняется, а затем проверите перед тем, как вручную вызвать метод в вашем controllerе.

Итак, в вашем controllerе:

 if (!ModelState.IsValid) { if (!model.Validated) { var validationResults = model.Validate(new ValidationContext(model, null, null)); foreach (var error in validationResults) foreach (var memberName in error.MemberNames) ModelState.AddModelError(memberName, error.ErrorMessage); } return View(post); } 

И в вашей модели:

 public bool Validated { get; set; } public IEnumerable Validate(ValidationContext validationContext) { // perform validation Validated = true; } 

Есть способ сделать это, не требуя кода шаблона в верхней части каждого действия controllerа.

Вам нужно будет заменить стандартное связующее устройство на свой собственный:

 protected void Application_Start() { // ... ModelBinderProviders.BinderProviders.Clear(); ModelBinderProviders.BinderProviders.Add(new CustomModelBinderProvider()); // ... } 

Ваш поставщик связующего устройства выглядит следующим образом:

 public class CustomModelBinderProvider : IModelBinderProvider { public IModelBinder GetBinder(Type modelType) { return new CustomModelBinder(); } } 

Теперь создайте настраиваемое связующее устройство, которое фактически заставляет валидацию. Здесь тяжелый подъем:

 public class CustomModelBinder : DefaultModelBinder { protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) { base.OnModelUpdated(controllerContext, bindingContext); ForceModelValidation(bindingContext); } private static void ForceModelValidation(ModelBindingContext bindingContext) { var model = bindingContext.Model as IValidatableObject; if (model == null) return; var modelState = bindingContext.ModelState; var errors = model.Validate(new ValidationContext(model, null, null)); foreach (var error in errors) { foreach (var memberName in error.MemberNames) { // Only add errors that haven't already been added. // (This can happen if the model's Validate(...) method is called more than once, which will happen when // there are no property-level validation failures.) var memberNameClone = memberName; var idx = modelState.Keys.IndexOf(k => k == memberNameClone); if (idx < 0) continue; if (modelState.Values.ToArray()[idx].Errors.Any()) continue; modelState.AddModelError(memberName, error.ErrorMessage); } } } } 

Вам также понадобится метод расширения IndexOf. Это дешевая реализация, но она будет работать:

 public static int IndexOf(this IEnumerable source, Func predicate) { if (source == null) throw new ArgumentNullException("source"); if (predicate == null) throw new ArgumentNullException("predicate"); var i = 0; foreach (var item in source) { if (predicate(item)) return i; i++; } return -1; } 
  • Выполнение проверки на стороне клиента для пользовательского атрибута
  • ASP.NET MVC - Пользовательское сообщение проверки для типов значений
  • Как пропустить проверку при нажатии на определенную кнопку?
  • Простой скрипт проверки формы jQuery
  • Какое правило Firebase предотвратит дубликаты в коллекции на основе других полей?
  • Подтвердите количество элементов has_many в Ruby on Rails
  • Проверка подлинности электронной почты с помощью jQuery
  • Проверка подлинности WinForm UI
  • Пользовательская проверка MVC: сравнить две даты
  • Установить проверку classа для динамического текстового поля в таблице
  • MVC DateTime validation - UK Формат даты
  • Interesting Posts

    Умножить поле по значению в Mongodb

    Модель, поддерживающая контекст «ApplicationDbContext», изменилась с момента создания базы данных

    Не удалось использовать ручку после очистки после использования командной строки

    Предотвратить несколько экземпляров данного приложения в .NET?

    Динамические свойства Objective-C во время выполнения?

    Прокрутка страницы вверх или вниз в Selenium WebDriver (Selenium 2) с использованием java

    Аккумуляторы Prolog. Действительно ли это «другая» концепция?

    Как использовать GWT EventBus

    Как использовать андроидный canvas, чтобы нарисовать прямоугольник с круговыми углами только на вершине и вправо?

    Что делает опция «Bitmap Caching» в клиенте удаленного рабочего стола?

    Где указаны значения по умолчанию для параметров командной строки по умолчанию?

    Мой ноутбук стирает диск d, а затем настроил раздел восстановления, чтобы я мог продать ноутбук

    Темный прозрачный слой над QMainWindow в Qt

    Как добавить кнопку динамически в Android?

    Определение выравнивания структур C / C ++ по отношению к его членам

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