What the heck is a ModelState error? Why do I care?

The following post is an email I sent out to my team reviewing why we care about ModelState in an Asp.NET MVC 3 project:

When you bind your views to a Model, you are basically telling MVC to keep track of all of the public properties in the class type that you bound the view to. When you send data to an mvc action via an HTTP request (POST, GET, PUT, DELETE, etc.), mvc uses a ModelBinder to take all the data you sent and shove it into the Model type that you specified as the parameters of the action. If there were any problems binding your data to the Model type specified, you get a model state error. Those errors are stored in the ModelState dictionary which is a key value pair collection where the key’s are all the propterty names of the binding type properties. If you encounter an error, the best practices scenario that MVC likes, is to return the invalid Model back to the View. When you do this, AND you have ClientValidationEnabled AND UnbotrusiveValidationEnabled AND you are using ValidationMessage or ValidationMessageFor, or ValidationSummary helpers on your form properites, wonderful things happen on the View; the error message of the Model State error is shown.

I want to point out another scenario which Rob [Gedelian] has taken advantage of. The preceding scenario involves ModelState binding errors, which only happen before the body of your Action code is executed. But what happens if you encounter an error, or an unexpected (but handled) situation in your action code. You can manually add a model state error to the collection. If you add the ModelState error using a key that is already on your form, you will be displaying back the error NEXT TO the invalid form property back on your view.

        public void CreateDocumentAsync(EmployeeDocumentViewModel viewModel)
            Request.Headers["X-Requested-With"] = "XMLHttpRequest"; // spoof ajax request headers in case of an error - we don't want to render the layout

            if (ModelState.IsValid && !FileUtils.IsValidDocument(viewModel.File.ContentType))
                ModelState.AddModelError("File", "Invalid file type.  Please upload a document.");

            if (ModelState.IsValid)
                new EmployeeCreateDocumentService(AsyncManager, viewModel);
                viewModel.New = true;
                viewModel.Error = true;
                this.AsyncManager.Parameters["viewModel"] = viewModel;

The “File” parameter is the key, which maps back to the view:

        @Html.EditorFor(e => e.File)
        <li class='validationSummary'>

The way Rob chose to display the errors was using an Html.ValidationSummary helper, but he could just as easily used the following:

        @Html.EditorFor(e => e.File)
        @Html.ValidationMessageFor(e => e.File)

As an aside, the reason Rob was able to use Html.EditorFor is because I created an MVC Editor template for the type HttpPostedFileBase:

@model HttpPostedFileBase
    var attrs = Html.Attributes();
    attrs = Html.AddMaxLengthAndRequiredToAttributes();
    attrs["class"] = "text-box single-line" + (attrs.ContainsKey("class") ? " " + attrs["class"] : string.Empty);
    attrs["type"] = attrs.ContainsKey("type") ? attrs["type"] : "file";
@Html.FileBox("", attrs)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s