简体   繁体   中英

Can I automatically trigger model validation inside a custom model binder?

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:

  1. Why does TryValidateModel(ModelState) not validate the form when ModelState has a reference to the same instance of the form that TryValidateModel(form) correctly validates?

  2. Why does TryValidateModel(form) cause the value of ModelState.IsValid to be updated?

  3. In general, why are the binders responsible for updating ModelState ?

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...)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM