ASP.NET MVC 2 Partial Validation

17 Mar

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.

About these ads

2 Responses to “ASP.NET MVC 2 Partial Validation”

  1. Asad Ali Butt March 17, 2010 at 9:58 pm #

    Thanks mate, was really informative.

  2. Silvia July 24, 2013 at 6:01 am #

    I’m no longer sure where you are getting your info, but great topic. I needs to spend a while finding out more or working out more. Thank you for excellent info I used to be looking for this info for my mission.

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

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: