Site Meter
 
 

Monthly Archives: February 2010

Partial Validation in ASP.NET MVC 2

It’s tiny tip time…

Since all the fuss about [Required] validators in ASP.NET MVC 2, the validation behaviour was changed in Release Candidate 2. Previously, the framework only validated fields that were actually posted in the form, whereas now it validates all the fields on any model object that the model binder gives you. Most people prefer this new behaviour, because they don’t like the idea that someone can avoid a [Required] rule just by using FireBug or similar to delete the HTML form field. That’s pretty understandable, and well done to the MVC team for agreeing to this change so late in the production cycle.

However, there’s a drawback to this change of behaviour. What about when you want partial validation (i.e., validating only a subset of your model’s fields)? Maybe your screen only provides input controls for a subset of fields. In fact, right now, I’m making a multi-step wizard, sharing a single model class across all steps (because it’s convenient). Obviously I don’t want to show errors on step 1 about fields that appear on step 2, especially not “A value for (some field you can’t see) is required.

Doing Partial Validation

In this specific case, the pre-RC2 behaviour would have been more convenient. I only want to validate the values that were actually posted on each step. A very simple way of achieving that is to use this action filter:

public class ValidateOnlyIncomingValuesAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var modelState = filterContext.Controller.ViewData.ModelState;
        var valueProvider = filterContext.Controller.ValueProvider;
 
        var keysWithNoIncomingValue = modelState.Keys.Where(x => !valueProvider.ContainsPrefix(x));
        foreach (var key in keysWithNoIncomingValue)
            modelState[key].Errors.Clear();
    }
}

Now, if you use this filter on a controller or action method…

[ValidateOnlyIncomingValues]
public class SomeController : Controller
{
   // ...
}

then the filter will discard any validation errors that correspond to fields that were not even posted during this request.

But what about security?

Obviously this means that someone can bypass my [Required] rules by modifying their HTTP posts so they don’t include any key-value pair for any given field.

This is no problem at all. My real validation logic is all in the domain layer, so it doesn’t really matter what happens in the UI layer. The validation feedback from the UI layer is only for the end user’s convenience – if they choose to bypass it, they’ll just get an error message later.