我可以在自定义模型绑定器中自动触发模型验证吗?
我有一个复杂的对象,我正在将其绑定到表单上。模型绑定器看起来像这样:
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var form = new MyForm();
var myObject = ...; //try to load up the object
/* logic to populate values on myObject */
form.MyObject = myObject;
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, new ValueProviderResult(form, "", CultureInfo.CurrentUICulture));
return form;
}
它正在做它应该做的事情;我从中得到了一个正确填充的 MyForm
,并且对同一 MyForm 实例的引用包含在 ModelState 中。但是,该表单未使用 DataAnnotations
或我的 CustomValidation
验证进行验证。为了进行验证,我必须在控制器中添加一个 TryValidateModel()
调用:
[HttpPost]
public ActionResult ProcessMyForm(MyForm form)
{
//ModelState has the MyForm instance inside of it
//TryValidateModel(ModelState); //this does not work
TryValidateModel(form); //this works
if (!ModelState.IsValid)
{
return View("Complete", form);
}
return RedirectToAction("Index");
}
它不仅调用我的自定义验证,而且还更新 ModelState.IsValid 的值。
除了我的标题问题之外,这还引发了几个问题:
为什么当
ModelState
引用同一实例时TryValidateModel(ModelState)
不验证表单TryValidateModel(form)
正确验证的表单是什么?为什么
为什么TryValidateModel(form)
会导致ModelState.IsValid
的值更新?一般来说,为什么绑定器负责更新
ModelState
?
I have a complex object that I'm binding off of a form. The model binder looks like this:
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var form = new MyForm();
var myObject = ...; //try to load up the object
/* logic to populate values on myObject */
form.MyObject = myObject;
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, new ValueProviderResult(form, "", CultureInfo.CurrentUICulture));
return form;
}
and it is doing what it's supposed to; I get a correctly populated MyForm
out of it, and a reference to the same MyForm instance is included in the ModelState. However, the form does not get validated using either the DataAnnotations
or my CustomValidation
validation. In order to cause that validation, I have to add a TryValidateModel()
call in my Controller:
[HttpPost]
public ActionResult ProcessMyForm(MyForm form)
{
//ModelState has the MyForm instance inside of it
//TryValidateModel(ModelState); //this does not work
TryValidateModel(form); //this works
if (!ModelState.IsValid)
{
return View("Complete", form);
}
return RedirectToAction("Index");
}
Which not only calls into my custom validation, but also updates the value of ModelState.IsValid.
In addition to my title question, this raises a couple of questions:
Why does
TryValidateModel(ModelState)
not validate the form whenModelState
has a reference to the same instance of the form thatTryValidateModel(form)
correctly validates?Why does
TryValidateModel(form)
cause the value ofModelState.IsValid
to be updated?In general, why are the binders responsible for updating
ModelState
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
ModelBinder 的职责是将请求中的值绑定到您正在使用的模型中。
ModelState 属性只是一个包含模型当前状态的字典。像错误列表一样查看模型状态。
当您有自定义 ModelBinder 时,您可以将请求中的值映射到您选择的类中。这最终将作为您的操作方法的参数。
我不同意你的观点,即 modelbinder 负责更新 ModelState,因为 ModelBinder 在绑定值时运行,在运行 TryValidateModel 之前它仍然可以具有 IsValid=true。
当您稍后运行 TryValidateModel(或 ValidateModel)时,它将使用您遇到的任何错误更新 ModelState 属性。您还可以使用不同类型的验证方法(DataAnnotations、IValidatableObject...)
The ModelBinder's responsibility is to bind values from the request into the model(s) you are using.
The ModelState property is just a dictionary containing the current state of you models. Look at modelstate like an errorlist.
When you have a custom ModelBinder you map the values from the request into the class of your choice. That will end up as a parameter into your actionmethod.
I wouldn't agree with you that modelbinders are responsible for updating the ModelState since the ModelBinder is run when it binds the values, it can still have IsValid=true before you run TryValidateModel.
When you later run the TryValidateModel (or ValidateModel for that matter) it will update the ModelState property with whatever errors you have. You can also use different types to validation methods (DataAnnotations, IValidatableObject...)