проблема проверки asp.net mvc - PullRequest
       3

проблема проверки asp.net mvc

3 голосов
/ 15 сентября 2010

Это не имеет никакого смысла для меня.

Посмотрите на эту ViewModel:

public class SelectService
{
    [Required]
    public int? SelectedServiceId { get; set; }
}

Посмотрите на это действие:

[HttpPost]
public virtual ActionResult SelectService()
{
    TryUpdateModel(WizardContainer.SelectService, "SelectService");
    TryValidateModel(WizardContainer.SelectService, "SelectService"); // if I remove this, ModelState.IsValid will always be true


    if (ModelState.IsValid)
    {
        return RedirectToAction("OtherAction");
    }
    else
    {
        return View(WizardContainer);
    }
}

Теперь прочитайте этот отрывок из Apress ASP.NET MVC 2 Framework от S. Sanderson:

Всякий раз, когда вы используете привязку модели для заполнения объекта модели - либо получая его в качестве метода действия или путем вызова UpdateModel () или TryUpdateModel () вручную - тогда DefaultModelBinder будет автоматически запускать валидаторы, связанные со всеми объектами модели, которые он обновил (т. е. те, где установил значение хотя бы для одного свойства). Если вы обновите объект модели любым другим способом, его валидаторы не будут запущены, если вы явно не укажете рамки для их запуска.

Так почему же тогда проверка никогда не происходит, когда я вызываю TryUpdateModel ()? Чтобы получить подтверждение, я должен явно проверить с помощью TryValidateModel ().

UPDATE

Вот очень похожее действие в том же контроллере, которое работает, как и ожидалось:

[HttpPost]
public virtual ActionResult Index(string nextButton)
{
    TryUpdateModel(WizardContainer.Index);

    if (nextButton != null && ModelState.IsValid)
    {
        return RedirectToAction("OtherAction");
    }
    else
    {
        return View(WizardContainer.Index);
    }
}

А вот это ViewModel:

public class Index
{
    [Required]
    public DateTime? SelectedServiceTime { get; set; }
}

Обновление 2

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

Посмотрите на отредактированное действие:

[HttpPost]
public virtual ActionResult SelectService()
{
    TryUpdateModel(WizardContainer.SelectService);
    //TryValidateModel(WizardContainer.SelectService, "SelectService"); // not needed anymore

    if (ModelState.IsValid)
    {
        return RedirectToAction("OtherMethod");
    }
    else
    {
        return View(WizardContainer.SelectService);
    }
}

Разница заключается лишь в том, что объект, который я передаю в TryUpdateModel (), - это объект, который я передаю представлению, а не свойство объекта, который я передаю представлению. Что за сделка?

1 Ответ

0 голосов
/ 15 сентября 2010

Я включил декомпиляции обоих методов TryUpdateModel и TryValidateModel ниже. Основное отличие, которое я вижу, состоит в том, что возвращение TryUpdateModel равно ModelState.IsValid, но я не вижу явного выполнения валидаторов в TryUpdateModel.

TryValidateModel фактически получает валидаторы и выполняет каждый из них. Должна быть небольшая разница между вашим рабочим и нерабочим делом. Я не могу сказать, что является основной причиной, но в вашем рабочем случае уже есть ModelState ошибок, добавленных в коллекцию ModelState.Errors при вызове TryUpdateModel. (ModelState.IsValid возвращает false, если в коллекции ModelState.Errors есть одна или несколько ошибок.)

TryUpdateModel:

protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel: class
{
    if (model == null)
    {
        throw new ArgumentNullException("model");
    }
    if (valueProvider == null)
    {
        throw new ArgumentNullException("valueProvider");
    }
    Predicate<string> predicate = delegate (string propertyName) {
        return BindAttribute.IsPropertyAllowed(propertyName, base.includeProperties, base.excludeProperties);
    };
    IModelBinder binder = this.Binders.GetBinder(typeof(TModel));
    ModelBindingContext context2 = new ModelBindingContext();
    context2.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(delegate {
        return base.model;
    }, typeof(TModel));
    context2.ModelName = prefix;
    context2.ModelState = this.ModelState;
    context2.PropertyFilter = predicate;
    context2.ValueProvider = valueProvider;
    ModelBindingContext bindingContext = context2;
    binder.BindModel(base.ControllerContext, bindingContext);
    return this.ModelState.IsValid;
}

TryValidateModel:

protected internal bool TryValidateModel(object model, string prefix)
{
    if (model == null)
    {
        throw new ArgumentNullException("model");
    }
    foreach (ModelValidationResult result in ModelValidator.GetModelValidator(ModelMetadataProviders.Current.GetMetadataForType(delegate {
        return model;
    }, model.GetType()), base.ControllerContext).Validate(null))
    {
        this.ModelState.AddModelError(DefaultModelBinder.CreateSubPropertyName(prefix, result.MemberName), result.Message);
    }
    return this.ModelState.IsValid;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...