Проверка модели представления после привязки пользовательской модели
У меня есть модель представления, которая реализует IValidatableObject
которая содержит строку и коллекцию другой модели представления, что-то вроде этого:
public sealed class MainViewModel
{
public string Name { get; set; }
public ICollection<OtherViewModel> Others { get; set; }
}
Моя проверка проверяет каждый объект в Others
против разных правил, используя контракт, предоставленный IValidatableObject
:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
foreach (var other in this.Others)
{
// validate or yield return new ValidationResult
}
}
Из-за сложной структуры реального MainViewModel
Мне пришлось создать пользовательский механизм связывания модели, который перестраивает модель и присваивает данные POST соответствующим компонентам. Проблема, которую я получаю, состоит в том, что ничего не проверяется, что приводит к ошибкам проверки на уровне контекста, поскольку это нарушает определенные ограничения базы данных, и я не уверен, что делаю неправильно - я предположил, что ModelState.IsValid
будет ссылаться на Validate
метод на моей модели зрения, но, похоже, не идет по этому пути.
Моя модель переплета выглядит так:
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
int modelId = (int)controllerContext.RouteData.Values["id"];
// query the database and re-build the components of the view model
// iterate the POST data and assign to the model where necessary
// should I be calling something here to validate the model before it's passed to the controller?
return model;
}
Любая помощь приветствуется!
Validator.TryValidateObject
ОК, кажется, я немного ближе. Теперь я могу получить IValidatableObject
метод для запуска, добавив следующее в мой пользовательский связыватель модели:
var validationResults = new HashSet<ValidationResult>();
var isValid = Validator.TryValidateObject(model, new ValidationContext(model, null, null), validationResults, true);
Кажется, что Validator.TryValidateObject
вызывает метод проверки и установки последнего параметра в true
заставляет его проверять все свойства. Тем не менее, я сейчас застрял с получением validationResults
к контроллеру, чтобы они могли быть использованы осмысленно.
2 ответа
Я должен был понять, что я мог бы использовать ModelState.AddModelError
благодаря пользовательскому связующему мне удалось теперь правильно настроить его, добавив следующее в свой пользовательский связыватель модели перед возвратом модели в контроллер:
var validationResults = new HashSet<ValidationResult>();
var isValid = Validator.TryValidateObject(model, new ValidationContext(model, null, null), validationResults, true);
if (!isValid)
{
foreach (var result in validationResults)
{
bindingContext.ModelState.AddModelError("", result.ErrorMessage);
}
}
return model;
Теперь это возвращает список всех ошибок на мою страницу и ModelState.IsValid
проверка на моем контроллере действие теперь возвращается false
,
Великий ответ Павла может быть преобразован в общий метод проверки и преобразования в ModelState
метод следующим образом (например, в помощнике или CustomModelBinder
база). Кроме того, привязки к проверенным свойствам сохраняются.
public static void DoValidation(ModelBindingContext bindingContext,
IValidatableObject model)
{
var validationResults = new HashSet<ValidationResult>();
var isValid = Validator.TryValidateObject(model,
new ValidationContext(model, null, null), validationResults, true);
if (!isValid)
{
var resultsGroupedByMembers = validationResults
.SelectMany(_ => _.MemberNames.Select(
x => new {MemberName = x ?? "",
Error = _.ErrorMessage}))
.GroupBy(_ => _.MemberName);
foreach (var member in resultsGroupedByMembers)
{
bindingContext.ModelState.AddModelError(
member.Key,
string.Join(". ", member.Select(_ => _.Error)));
}
}
}