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

У меня есть модель представления, которая реализует 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 контроллеру, чтобы их можно было использовать осмысленно.


person Paul Aldred-Bann    schedule 03.12.2012    source источник


Ответы (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.

person Paul Aldred-Bann    schedule 03.12.2012
comment
где мне нужно разместить этот код: контроллер и действие, а также в привязке модели и где? На самом деле я получаю эту ошибку, пожалуйста, помогите. - person Rajpurohit; 26.12.2013
comment
@Rajpurohit Вы поместите приведенный выше код в свой класс привязки пользовательской модели. - person Paul Aldred-Bann; 27.12.2013
comment
в formeach вы также можете получить MemberNames. string memberName = (result.MemberNames! = null && result.MemberNames.Count () ›0)? result.MemberNames.First (): string.Empty; bindingContext.ModelState.AddModelError (имя члена, результат.ErrorMessage); - person Dragos Durlut; 13.09.2017

Отличный ответ Пола можно реорганизовать в общий метод проверки и преобразования в 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)));
        }
    }
}
person StuartLC    schedule 26.03.2014