This post was inspired by the technique from Steven Sanderson’s blog post on this same topic.  Since the introduction of validation with the DataAnnotations, the behavior with ASP.NET MVC 2 now is that the framework validates all your model fields when you post a form, regardless of how many fields the form submitted.

This brings some frustration if you need to do some partial validations.  For example if you need to validate just a subset of the fields in your model, and you create a view just for those fields, but when you submit the form you see errors for all the other fields in your model that were not shown in the view. This will bring some confusion for your users.

Partial Validation in Asp.NET MVC

I recently had this scenario where I had a model that goes through four stages. A user creates a document (View 1), submits to the first approving officer(View 2) who approves and submits to the second approving officer(View 3) , who approves and finally submits the approved document back to the initial user(View 4).  Each step has a different view, all of which are bound to the same model. I wouldn’t want the second approving officer to see errors for the third approving officer, etc.

So I tried to use the custom filter “as is”  from Steve’s blog post but it didn’t work.  UpdateModel was throwing the model errors without applying the filter.  I coudn’t trace the source for this behavior. So I modified the code into some kind of a hack just to get the job done, right there in the controller Action.

How it works

I wrap the UpdateModel process in a try catch.  When it throws and exception I catch it and clear all the errors from ModelState for the model fields that were not included/posted in the form.  I then validate the model, now for the fields that were posted with the form and catch any model errors . I then resubmit the view with the right error messages.  It works like a charm.


[HttpPost]
public ActionResult Edit(int id, FormCollection formValues)
{
Document doc = GetDocumentFromDB(id);

try
{
var valueProvider = formValues.ToValueProvider();

try
{
//tries to update all properties in the model
//throws an exception for properties which were not posted in the form
UpdateModel(doc, valueProvider);
}
catch (Exception)
{
//clear all the errors for the properties whose values were not posted by the form

var keysWithNoIncomingValues = ModelState.Keys.Where(x => !valueProvider.ContainsPrefix(x));

foreach (var key in keysWithNoIncomingValues)
{
ModelState[key].Errors.Clear();
}
}

//Now we validate only against those properties whose values were posted in the form.
if (ModelState.IsValid)
{
// do your stuff here

//commit changes to the database
docsRepository.SaveChanges();
else
{
return View(doc);
}
}
catch (Exception)
{
return View(doc);
}

}

And thats it.  If you can find a way to create an action filter for the functionality then it’ll be even better because you can use the same attribute in different places in your code and hence DRY.  Hope it was helpful.  Till next time, yours truly.

ASP.NET MVC 2 Partial Validation
Tagged on:             

One thought on “ASP.NET MVC 2 Partial Validation

Leave a Reply

Your email address will not be published. Required fields are marked *