这对我没有任何意义。
看看这个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);
}
}
现在阅读S. Sanderson的Apress ASP.NET MVC 2 Framework中的这个例外:
每当使用模型绑定来填充模型对象时 - 通过将其作为操作方法接收 参数,或通过手动调用UpdateModel()或TryUpdateModel()然后DefaultModelBinder将 自动运行与其已更新的所有模型对象相关联的验证器(即,它所在的模型对象) 已在至少一个属性上设置了值)。 如果以任何其他方式更新模型对象,除非明确说明,否则不会运行其验证器 运行它们的框架。
那么,当我调用TryUpdateModel()时,为什么验证永远不会发生?要进行验证,我必须使用TryValidateModel()显式验证。
这是一个非常类似的操作,在同一个控制器中按预期工作:
[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; }
}
我改变了一些东西,现在它表现得像预期的那样,但我仍然不明白为什么。
查看已编辑的操作:
[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()的对象是我传递给视图的对象,而不是我传递给视图的对象的属性。什么交易哟?
答案 0 :(得分:0)
我在下面添加了TryUpdateModel
和TryValidateModel
方法转换。我看到的主要区别是TryUpdateModel
的返回值为ModelState.IsValid
,但我发现在TryUpdateModel
中没有明确执行验证程序。
TryValidateModel
实际上获取验证器并执行每个验证器。您的工作和非工作案例之间必然存在一些细微差别。我不能说根本原因是什么,但在您的工作案例中,当您致电ModelState
时,ModelState.Errors
集合中已添加TryUpdateModel
个错误。 (如果ModelState.IsValid
集合中存在一个或多个错误,则ModelState.Errors
会返回false。)
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;
}