Site Meter
 
 

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.

31 Responses to Partial Validation in ASP.NET MVC 2

  1. What don’t you just set Exclude, Include lists for default model binder instead?

    UpdateModel(product, new string[] { “Name”, “Price” });

    or

    [Bind(Include("Name,Price")]
    public class Product { … }

  2. Steve

    Koistya – because that wouldn’t affect which properties were validated. The behaviour in ASP.NET MVC 2 RC 2 is that it validates all fields, no matter which ones have values bound to them.

  3. IMHO every view should have it’s own model, so for the multi-step wizard you’re referring to you should have an equal number of view models (or better call them form models) as you have steps.

    In that case there’s no problem, because the model only contains the properties and validation neccessary for that step.

  4. Absolutely agreed with Jorrit.

  5. Steve

    Jorrit, Koistya – Most of the time I agree with you and, for data entry scenarios, typically have one view model per view. However, I also like to have the flexibility to do things differently from time to time!

    In some scenarios I’ve found that sharing view models (or portions of them) between closely related views has been helpful for keeping things simple and avoiding repetition.

  6. Quooston

    One of those “cake and eat it” type stories. Nothing wrong, it’s the lesser of two weavles so we have to go ahead with it. It’s easy enough to work around and it’s for the greater good!

  7. Good to know!

    I can’t think of anything I’d need it for yet, but if I do, I’ll know where to come for help! Thanks!

  8. Would be good if we could apply to a specific parameter.

    I wish the MVC team would have allowed us to turn this off using the Bind attribute.

  9. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #544

  10. Naz

    Hi Steve,
    Thanks for the post,

    Is there a way of not having validation kick in in the first place this would be especially userfull when there are remote validators which can do costly database lookups eg. Username exists checks.

    Just like the Bind syntax maybe a Validate attribute that has you can apply to your Model which tells the model binder which ones to include or exclude for validation

    Naz

  11. Hi Steve, Thanks for this. I had a serious problem with this issue over the weekend.

    I have a model that has to be approved by 3 people at different times. So I have 3 different views for each approval level. It was difficult to get it working with MVC2.

    Your solution has been like a Godsend. Solved my problem. Cheers.

  12. Faced the problem! Thanks dude!

  13. Pingback: 9eFish

  14. Thanks for the post, Steve. Your book about ASP.NET MVC 1.0 is awesome, by the way, can’t wait until book about v2 come out.

  15. Nice article, thank you!

  16. imperialx

    Thanks for the info, but as MVC 2 RTM is out, does the Exclude parameter back in action?

  17. Pingback: ASP.NET MVC 2 Partial Validation « Programming and Software Development

  18. Great info. New developers or new to MVC miss out some of the basic issues. You really figure out some very important point. Do appriciate

  19. Shan

    Very handy in scenarios where a form may or may not show a username and password prompt, in addition to the rest of the form. Thanks!

  20. You can apply this pattern for all Get Requests.

    Thx for the tips.

  21. Nabeel Farid

    Hi Steve,

    Great post.

    I am using your XVal with NHibernate Validator in my ASP.NET MVC 2 application.

    I would like to know if there is an elegant solution for dealing with the following two model binding failure scenarios for non nullable type:-

    - when the data the user entered isn’t compatible with the data type (for example, typing in “abc” for an integer field). The default message for this is: “The value [AttemptedValue] is not valid for [Property].”

    - when the user did not enter any data for a field which is not nullable (for example, an integer field). The default message for this is: “A value is required.”

    How can i take care of these two vanilla messages? The DefaultModelBinder uses [Required] attribute from
    DataAnnotationsModelValidatorProvider for the second scenario. Since I am not using DataAnnotations and
    instead using NHibernateValidator, I would like to know how to take care of the above issues. Also, like you always recommend, I am doing validation in my domain layer.

    So I wonder what do you recommend. I have thought about the following two approach but

    - Allow the model binding validation errors to occur, and then ignore and remove them from ModelState in my action method and refill it with my custom validation errors?
    - Derive a custom model binder from and defaultmodel binder and override the onModeUpdated method ignoring all the validation or probably clearing ModelState.Errors?

    Thanks
    Nabeel

  22. Barry

    Thanks Steve,
    I built a multi-step wizard based on the example in your book which worked perfectly with MVC 1, but didn’t play ball with MVC 2′s built-in validation. Thanks to this post it’s now working fine again!

  23. Sajad Deyargaroo

    I have a scenario where I need to show/hide fields dynamically (I am doing that using jQuery). I want to skip the validation for the fields, which user doesn’t even see on the screen. I can use a hidden bool field that will tell me on server whether the actual field was shown to the user or not, is there any way to do this kind of conditional validation in MVC 2 e.g., if hidden field is true then validate the field else not.

  24. Jorrit wrote:

    “IMHO every view should have it’s own model”

    I cannot disagree with this more. Every view should have its own model? That is absolutely ridiculous. Take the simple example of the user account. You are saying here then that the register user view and edit user view should have two completely separate models, when most likely the only difference between these models is that one is going to let you set your username/password and the other will not. All other fields on the user will be the same between the views. Seems like this contradicts another principle that everyone using MVC seems to clammer on about – Don’t Repeat Yourself.

  25. Stephen Redd

    Is there a similarly elegant way to deal with partial model updates when you are using a view-model instead of directly passing the annotated entity as the model?

    For example:

    public virtual ActionResult Create(FormCollection collection)
    {
    try
    {
    Ticket ticket = new Ticket();
    UpdateModel(ticket, “NewTicket”, collection);
    if(TicketService.CreateTicket(ticket))
    {
    RedirectToAction(“Success”);
    }
    else
    {
    return View(new TicketCreateViewModel(ticket));
    }
    }
    catch { return View(new TicketCreateViewModel(ticket)); }
    }

    Action Filters have already happened long before you get to the UpdateModel() method call… You can pretty much use the same code to remove the unwanted model state by putting the code directly in the controller, but it lacks the elegance.

    I’ve worked around it myself by creating a custom model binder and combining it with your ActionFilter attribute, but that is a LOT of work to go through for what amounts to a VERY simple and VERY common scenario. Pretty much any wizard style UI would run into this, and you run into it when you have several of your entities fields being auto-populated by back-end business logic prior to the database commit.

  26. “In some scenarios I’ve found that sharing view models (or portions of them) between closely related views has been helpful for keeping things simple and avoiding repetition.”

    Code repetition can be avoided using inheritance:

    class MyViewModelStep2 : MyViewModelStep1
    {
    [Required]
    string AnotherField {get;set;}
    }

  27. Ben

    Hi Steve, would you have an example project using this technique?

    I added this to my project, along with the hack to MicrosoftMvcValidation.js (Dev10 Bug #920136), and it still won’t skip validation on disabled elements.

    Decorated my controller with [ValidateOnlyIncomingValues] and intellisense isn’t complaining, so not sure what else to do.

    (Sorry, I’m kinda dumb at times and only learn from example…) :)

  28. Abid Rahman

    Intelligent solution to a real problem. Thanks Steve.

  29. Pingback: ASP.NET MVC 2: validation and binding issues with rich-text input, DataAnnotations, view-models, and partial model updates » The Scribbler

  30. Pingback: MVC 3 – Only display/use certain model properties | PHP Developer Resource