Search code examples
asp.net-core-mvcmodelstatecustom-model-binder

ModelState.IsValid is false prior to validation


We wrote a custom model binder that overrides the CreateModel method of the ComplexTypeModelBinder so that we can have injection into our ViewModels instead of having to pass the injected clients and repos to our model from the controller.

For example, for a model like this:

public class ThingViewModel 
{
    public ThingViewModel (IThingRepo thingRepo) {}
}

In our controller we can do:

public class ThingController : Controller
{
    public IActionResult Index(ThingViewModel model) => View(model);
}

And this works pretty well, here's the override part of the custom model binder:

protected override object CreateModel(ModelBindingContext bindingContext)
{
    var model = bindingContext.HttpContext.RequestServices.GetService(bindingContext.ModelType);
    if (model == null)
        model = base.CreateModel(bindingContext);
    if (bindingContext.HttpContext.Request.Method == "GET")
    {
        bindingContext.ValidationState[model] = new ValidationStateEntry { SuppressValidation = true };
    }
    return model;
}

Pretty straightforward stuff.

The problem, is that in our GET action methods, if we use a ValidationSummary in the view, because validation was not run, the ModelState.IsValid is false, even though there are 0 errors... this causes the ValidationSummary to show up empty with a red border around it. An annoying work-around for this is to call the ModelState.Clear() method prior to sending the model into the view. Can I somehow change it so that IsValid is defaulted to true when validation has not been run yet? Or is there a better way?


Solution

  • This issue is not related to IoC model binding. MVC has an issue of still rendering an empty container for your validation summary, even if you have no validation errors. Two possible work arounds include:

    1. Create a partial that wraps the validation summary. In that partial, check for any errors in your model state before rendering the validation summary. Use that partial in place of where you would have used the stand alone validation summary.
    2. Add some CSS that hides the containing div if it does not contain any populated or visible list items. If there are no visible error list items, the container's display should be none.

    See this for additional info: Related Question