Site Meter
 
 

Model-based Client-side Validation for ASP.NET MVC

For quite a while, I was unsure how to go about doing validation in ASP.NET MVC. By default, it’s incompatible with the ASP.NET <asp:XyzValidator> server controls, so this gives us an opportunity to come up with something newer and better.

There have been a couple of great efforts from the community, including Juergen Baeurle’s MVC Validator Toolkit, and Matt Hawley’s MVC UI Validation Framework (now part of MVC Contrib). I wasn’t really satisfied with either, because they take validation out of the domain model and into the application’s UI (no offense guys, what you’ve done is cool).

So, check out my first ever screencast – 6 thrilling minutes of non-stop coding action, in which you get to add both server-side and breathtakingly fit client-side validation to an ASP.NET MVC application, while keeping all the validation rules right in the domain model. Whoo!

Oh noes! Either your feed reader has removed the screencast, or you haven’t enabled Javascript and Flash. You’re missing out!

For those of you that don’t have time for screencasts (like me, normally), here’s how to get the client-side validation goodness in your ASP.NET MVC application. I’m using Castle Validator for the server-side bits, and Live Validation for the client-side bits, fused into one terrifying alien beast hell-bent on ultimate data purity.

Instructions

1. Download and reference MvcValidator.dll and Castle.Components.Validator.dll (from the Castle project). In your master page, add a reference to the Live Validation script (preferably a local copy of it):

<script src="http://www.livevalidation.com/javascripts/src/1.3/livevalidation_standalone.compressed.js"></script>

2. Add validation attributes to your model object.

public class Person
{
    [ValidateNonEmpty("Please enter a name")]
    public string Name { get; set; }
 
    [ValidateNonEmpty("Please enter an email address")] [ValidateEmail]
    public string Email { get; set; }
 
    [ValidateNonEmpty("Please enter an age")] [ValidateInteger]
    public int? Age { get; set; }
}

3. Drop an Html.ClientSideValidation into your view:

<% using(Html.Form("Home", "SubmitPerson", FormMethod.Post)) { %>
    <p>Name: <%= Html.TextBox("MyPrefix.Name", ViewData.Name) %></p>
    <p>Email: <%= Html.TextBox("MyPrefix.Email", ViewData.Email)%></p>
    <p>Age: <%= Html.TextBox("MyPrefix.Age", ViewData.Age)%></p>
 
    <%= Html.ClientSideValidation(ViewData, s => "MyPrefix." + s) %>
    <%= Html.SubmitButton() %>
<% } %>

4. Strut, pose, be smug. You’re done!

Optional steps:

5. Add server-side validation keyed off the same validation attributes, using Castle Validator’s ValidatorRunner (the screencast shows this in action before the client-side validation).

6. Add CSS rules to get the red/green border effect as shown in the screenshot.

Downloads

Thoughts

I’d really love to see something along these lines baked into the official MVC framework, perhaps following Castle’s example of having a pluggable system for emitting Javascript for particular validation checks, so folks could integrate it with client-side validation libraries of their choice. (In my version, I’ve just hard-coded it to work with Live Validator.)

kick it on DotNetKicks.com

82 Responses to Model-based Client-side Validation for ASP.NET MVC

  1. Andy

    Validation attributes seem to be coming in System.ComponentModel.DataAnnotations from the scaffolding work in ASP.NET Dynamic Data. I hope that work from Microsoft develops quickly. I assume they are waiting for the updated previews of MVC before a newer version of MVC Dynamic Data is done, which should hint at the direction for validation.

    Yes, I do think this code looks far simpler to integrate and more elegant than the current code in MVCContrib for validation. Many thanks for the code.

  2. Kwadwo

    Thanks. This is great.

  3. Pingback: Links Today (2008-04-30)

  4. Pingback: Reflective Perspective - Chris Alcock » The Morning Brew #85

  5. Brilliant! What about validating the model on the serverside with the same attributes?

  6. Steve

    Hey Scott,

    It’s quite easy to do the same validation on the server too. I didn’t make a big point of it, but it’s shown in the middle of the screencast somewhere! Also, the demo project does this.

  7. Steve, thank you for posting this — its exactly what I was trying to do (perform validation with out having code in the UI)

  8. Doug Wilson

    Fantastic! Now to make those attributes work with WinForms as well.

  9. Robert Dean

    Very nice. Your solution is way more elegant than the stuff I was coming up with. Thanks for the great post!

  10. Very Coooooool Post!!!

  11. This is a nice way of dealing with validation.
    However, in this sample the error message is hard coded in the attribute. How would you go about internationalizing this if it became a requirement?

  12. Steve

    Anastasiosyal – that’s definitely a good point, and there are also other cases where you’d want to vary the message. (e.g. “Please enter a name” OR “Please enter your name” depending on context).

    A couple of things to consider:

    [1] Instead of having fixed strings in the validation attributes, you could have references to resource file entries. It might be cleaner if you add explicit support for that to Castle Validator.

    [2] You could add placeholders into the error message strings, e.g. “Please enter {owner} name”, then add means of passing parameters to Html.ClientScript, e.g. Html.ClientScript(ViewData, new { owner = “your” })

  13. Justin

    I’d really like to be able to use this as it’s a lot cleaner than what I’ve been doing. The problem I see with the attribute based validation is when used with code generators, i.e. subsonic/linq2sql etc. As far as I know there isn’t any way to decorate properties with partial classes, although I do remember seeing something about this for dynamic data. Any thoughts on this?

  14. Nicolas

    How to decorate your model with attributes if this model has been generated by the VS Linq to Sql designer ?

  15. Steve

    Justin and Nicolas,

    That’s a good question, and I hadn’t thought of that previously. When I use LINQ to SQL, I prefer to write the class definition and mapping manually (not using the code generator), so of course there’s no problem.

    If you really do want to use the codegen, I’d say you have two options:

    [1] Add ICustomTypeDescriptor on to the partial class, then implement GetProperties() to return the properties with validation attributes added. This will work because MvcValidation.dll inspects your model object using System.ComponentModel instead of raw reflection.

    [2] Create some other interface, ICanHasValidationPlz, and attach it to the partial classes. Then change the ClientSideValidation() method to check for your ICanHasValidationPlz interface, calling some special “GetValidationAttributes(string propertyName)” method on that interface where implemented (falling back on ComponentModel if not).

  16. Nicolas

    Thank you Steve. These are 2 nice possibilities.

  17. Andy

    I’m supprised that the “buddy class” approach for defining (validation) metadata for generated classes from Dynamic Data isn’t getting more coverage in blogs. As it really could become a standard approach.

    http://blogs.msdn.com/davidebb/archive/2008/03/06/dynamic-data-at-mix-and-upcoming-changes.aspx

  18. Steve

    Good point Andy. That would be an effective workaround here.

  19. Pingback: Wöchentliche Rundablage: ASP.NET MVC, Live Mesh, Silverlight, .NET… | Code-Inside Blog

  20. Pingback: Weekly Links: ASP.NET MVC, Live Mesh, Silverlight, .NET… | Code-Inside Blog International

  21. You have just plugged LiveValidation JS library support and used Castle validators.
    It would probably be more preferable if you’d use Castle’s java-script support for that.
    Not sure what about ASP.NET MVC.

    Anyway, thanks for sharing you work.

  22. Steve

    Hi Dmitriy -
    Yes, I did use Live Validation and Castle Validator, and in fact I said so in the blog post, and in the screencast! It’s not a secret… :)

    The ASP.NET MVC element is mainly demonstrating how to use this style of validation neatly, since up until now I hadn’t seen anyone else doing so with this platform. I’ve supplied an HTML helper method that, I hope, makes it much easier.

    > It would probably be more preferable if you’d use Castle’s java-script support
    I did try that at first, but it wasn’t as streamlined as I wanted (it requires you to inject code both at the top and bottom of the <form>), and I’m aiming for maximum slickness here. Plus, for this task I prefer Live Validation above jQuery and fValidate, so I needed to write a custom provider anyway.

  23. Very very cool. I’m going to try this as soon as I get back into work.

  24. Pingback: ASP.NET MVC Resources « HSI Developer Blog

  25. chopen

    Steve, could you provide one example implementing the solution that you proposed: “Add ICustomTypeDescriptor on to the partial class, then implement GetProperties() to return the properties with validation attributes added. ”

    Thanks

  26. Chris McDermott

    I think this is a nice add on to ASP.NET MVC. I have one question though, and it’s something that has always bothered me about using domain objects to back pages directly in Java and now in C#.

    As both languages are statically typed we can’t rely on them to take any form based content and validate server side. For example, using server side validation only, putting “woo” into the age field in your example gives me a “FormatException: Input string was not in a correct format.”.

    So to my question, is there anything that can be done to keep the domian strongly typed, i.e. don’t put a ‘string ageAsString’ property on it, and still do all the validation on the domain object using the Castle attributes? Sadly, I expect the answer is no.

  27. Steve

    Hi Chris

    You are right about the FormatException. It happens because, in the demo code, I call BindingHelperExtensions.UpdateFrom(…) to populate the model object, but don’t make any effort to catch PopulateTypeException that it (supposedly) throws in this case, telling you which field it was unable to populate.

    If you’re aiming for production-grade code, and aren’t happy to rely on client-side validation, you need to catch these and respond appropriately. This is a bit awkward because there isn’t an obvious way of mapping the PopulateTypeExceptions to your own friendly error messages.

    Also note that in CTP3, BindingHelperExtensions.UpdateFrom(…) seems to have a bug in that it doesn’t throw the PopulateTypeExceptions at all. It may just be my mistake though – I haven’t properly confirmed this.

  28. rajendra

    I sm downloading the source code but have a error
    The name ‘RenderView’ does not exist in the current context

  29. Steve

    Hi Rajendra – are you using the new CTP3? If so, that was released after I wrote this blog post, and it changes the API slightly. You need to replace RenderView() with View(). I’m not going to update this blog post for CTP3, because the current indication is that fairly soon the MVC framework itself will have a similar (presumably better) validation feature built-in.

  30. Rajendra

    Thnks Steve
    I have implemented all but I didnt see Red Green border to textbox for validation..
    I copied css also

  31. Pingback: MVC Framework preview 3, first contact « Frenchies Under Down

  32. allen

    I think this is a nice add on to ASP.NET MVC. but I have a prblem regarding I want to do many validations on a single textbox How to do that

  33. Steve

    Allen, you can add multiple validation attributes to each model field. For example, as shown in step 2 above,

    [ValidateNonEmpty("Please enter an age")] [ValidateInteger]
    public int? Age { get; set; }

  34. allen

    thats working,
    dynamically add ValidateRegExp to a single textbox

  35. Mike

    Great, you really understand the problem domain. Validation rules on the model, remembering the entered data, easy insertion of client side validation framework.

    You should still work on this some more, because it’s just so nice.

  36. Hi Steve,

    Excellent post. I’m investigating MVC for a new project and validation has been one of my major concerns, but this is really nice.

    I do have a question: Can you explain where Html.ClientSideValidation is coming from? That is, where is it declared? Is this part of the Castle dll? Or something else? I’d like to understand exactly, in more detail, how the Live Validation script is getting wired to the form.

    Thanks so much,
    Adam

  37. Steve

    Hi Adam

    Html.ClientSideValidation() is defined in the MvcValidation.dll offered as a download with the post. This generates the appropriate JavaScript to get Live Validation running.

    Steve

  38. chopen

    Hi Steve,

    I downloaded the source code, opened the solution and run the web demo and everything works fine.

    But, when I compile the MvcValidation project and use the dll generated in other web project I get an error in the Html.ClientSideValidation(ViewData) line. The error is: “ClientSideValidation’ is not a member of System.Web.Mvc.HtmlHelper”

    If I download the dll directly from your link, I put in the other same web project everything works correctly. What I missing when compile the MvcValidation project?

    TIA

  39. Steve

    Chopen – not sure, it’s probably a namespace issue. Make sure the extension method is in a static class that’s in the System.Web.Mvc namespace (or better still, put it in a custom namespace, then reference it in your web.config file under “namespaces”>

  40. Hi Steve,
    I have just started playing with your validation procedures. Nice work. I downloaded the source and updated the references so that it seems to work with MVC Preview 3.
    ValidateNonEmpty(“message”) and ValidateInteger(“message”) both behave nicely (except my error message is not displayed if the Integer does not validate). I get a NullReference exception when using ValidateLength(9, “Message”). Have you used ValidateLength?
    Any help appreciated.

  41. Hi Steve,
    Re my problem with ValidateLength.
    I have never used Castle before but poked about using Reflector and have now modified ValidationScripsHelper.ClientSideValidation to add
    v.Initialize(new CachedValidationRegistry(), null);
    immediately after the call to attrib.Build();
    ValidateLength now seems to work, but have I broken something else?
    thanks

  42. Steve

    Paul, sorry I didn’t respond sooner. Well spotted – there was a problem with [ValidateLength], and you found what seems to be the best solution.

    When I tried, I had to order the lines of code slightly differently to what you described. This seems to fix it:

    IValidator v = attrib.Build();
    v.ErrorMessage = v.ErrorMessage ?? LiveValidation.UnspecifiedMessage;
    v.Initialize(new CachedValidationRegistry(), null);
    v.ApplyBrowserValidation(null, InputElementType.Undefined, generator, null, null);

    If I develop this further (which I will do only if the MVC framework itself doesn’t have adequate validation built-in, but ScottGu suggested that it *will* have decent validation) then I’ll probably replace Castle Validation completely with something more straightforward.

    Thanks for the heads-up on this.

  43. Seb

    Hello,
    Great work man!
    I have a question. Could I use this validator on interfaces??

    thx

  44. Seb

    Hello and thanks for your excellent job!
    What about ValidateDate / ValidateDateTime attributes?? I must develop my own validator in the livevalidator.js file?

    thx

  45. Steve

    Hi Seb,

    [1] I guess you mean you have an interface, e.g. IHasNonEmptyName defining a “Name” property with some validation attributes, and your model object implements that interface. The code as I provided it won’t scan the model object’s interfaces, so you’d need to amend it to do so. Try updating ValidationScriptsHelper.ClientSideValidation() to iterate through the model object’s list of interfaces, considering all their properties.

    [2] DateTime validation wasn’t supported by Live Validator. If you want to add that, try updating LiveValidationProvider’s SetDate() method, perhaps causing it to render a “custom” validator like SetValueRange() does.

  46. Lee

    Brilliant post! Super sweet!

  47. Good stuff. I had to modify it to get it to work with (what I believe to be) the latest and greatest Castle and MVC DLL’s (in particularly adding a couple of stub implementations of methods in IBrowserValidationGenerator).

    Also to anyone who has trouble after updating to use preview 3 make sure to update this line:

    // (add .Model)

    Otherwise you’ll waste time trying to validate your view data rather than the model.

  48. Actually I have a question, have you come up with a way of validating sub-objects. For example if a Person has an Address have you worked out a nice way to validate both together or would we just validate them seperately?

  49. Steve – in tying your validation to the domain object properties via atrributes are you not also setting the UI validation in stone at the point you decorate the properties in this model?
    For example a registration form on mulitple websites (using same domain model) that allows different compulsory fields on a user object per site would not be achievable.
    Having your validation constructs outside the domain objects would allow the validation fields to be determined at runtime and thus have different UI validation patterns and make the domain -> UI validation less rigid.

  50. Steve

    @Colin – good point. No, it doesn’t try to recurse down the object graph. How would you decide how far to go? Wouldn’t you risk causing unnecessary database queries if the domain model used lazy loading? I wonder if it would be simpler to avoid it, forcing the programmer to add an explicit Html.ClientSideValidation for each object.

    @Justin – yes, the idea with attribute-based validation is to validate rules that are universally applicable for a given type of domain entity (the sort of thing you’d have DB constraints for), not rules that are applicable only on certain screens or for example based on the state of other domain entities. For these more complex scenarios, you’d need some other means of validation. Whether these two types of validation could be integrated into a single system is an interesting question.

  51. I love your implementation of Client/Server side validation using MVC. I think its the way to go compared to the MVCContrib project. The rules definately need to be on the model.

    I don’t know if its a coincidence or not, but shortly after I integrated the code above w/ livevalidation it seem my submit buttons work fine, but my buttons no longer work in IE7…

    Example: <button onclick=”alert( ‘Clicked!’ ); return false;”>Test</button>

    I’ll keep trying, but I wondering if you have heard of this before or seen it personally.

  52. Steve

    Hi Elijah, I haven’t heard of or seen anyone else having that problem. Does your button start working again if you remove the LiveValidation script? If you want to follow this up please email me directly. Cheers.

  53. @Steve
    You could be right on just validating each object seperately, however you could also use attributes to define the ownership of the objects (so on the Address property on Person you have an attribute that specifies to validate into the Address). Not important thought.

    One thing I did notice is that regular expressions are not currently supported, are you planning to add them at some stage?

  54. Steve

    Colin, you could add regular expression support fairly easily, as LiveValidation has decent support for it.

    However, I don’t expect to develop this code further because, by the time ASP.NET MVC is finally released, it will contain a comparable validation system of its own. I’ll only develop this code futher if ASP.NET MVC’s built-in validation system turns out to be inadequate.

    Roll on MVC RTM!

  55. Seb

    Hello Steve,
    Do you know how could I use “RunWhen” property and if I have a well using of it.
    In my project, I have to write some fields, ans 2 in particular (Login and Password). I can write no Login and no Password, but if I’m writing a Login, I must write a Pwd and vice versa.

    Is the RunWhen property a good solution?

    Thx

  56. Steve

    Hi Seb, I’m not sure whether Live Validator supports any equivalent of “RunWhen”. If it does, then maybe you could extend MvcValidator.dll to support it.

    Sorry I can’t be much more helpful right now. I’ll only be working on this if ASP.NET MVC’s forthcoming validation feature doesn’t provide an adequate solution on its own.

  57. Seb

    Do you know a release date about this ASP.NET MVC Validation ?

  58. Pingback: To (ASP.NET)MVC or not to MVC (or, ASP.NET MVC Hyperlink Acupuncture) « HSI Developer Blog

  59. Pingback: Steve Sanderson’s blog » Blog Archive » Thoughts on validation in ASP.NET MVC applications

  60. Pingback: Client & Server Side Validation in ASP.NET MVC | Emad Ibrahim

  61. Pingback: To (ASP.NET)MVC or not to MVC (or, ASP.NET MVC Hyperlink Acupuncture) | The Freak Parade

  62. Mark

    Great Article. Is it possible to perform the same functionality using the Validation Application Block in Entlib? What is the equivalent interface to the IBrowserValidationGenerator?

  63. I have the exact same problem Elijah has in post 51. + does no longer work when I add LiveValidation to my page. I’m using PHP-code, so the problem is not in your code, but it has to be similar. Any ideas yet ?

  64. Pingback: ASP.NET MVC Validation For Custom Models « Precursor to a Thought

  65. Yousof

    Hello, thank you very much, it is really great.
    I tried to compile the demo but I got this error:
    The type or namespace name ‘HtmlHelper’ could not be found (are you missing a using directive or an assembly reference?) path:\MvcValidationSourceAndDemo\MvcValidation\MvcValidation\ValidationScripts.cs MvcValidation

  66. Alexander Ekzarov

    Hi, Steve. Great post. I have a question for you. Is there a posibility to make validation on page load. I mean, how to decorate required fields for user? In web forms, I did it Valiadte() in Page_Load…

  67. Steve

    @Alexander – I’m afraid I don’t really understand your question. What is “page load” in the context of an ASP.NET MVC application?

  68. Alexander Ekzarov

    When I get on my page for a first time, I can`t see any required fields. To know them, I should submit. But, how I can see them immediately on first time.

  69. Steve

    @Alexander – aha, I see! Thanks for clarifying. It’s normal to simply put an asterisk (*) or some other symbol beside a required field rather than showing the validation error message. But if you do want to show validation errors when the form first appears, you could use JavaScript to invoke validation. I can’t remember what LiveValidation method you need to call, but I guess you could do it via document.getElementById(‘myForm’).submit().

  70. validation doesn’t belong in the domain model. A domain object might need different validation depending on what state its in. For example, something thats in “Draft” mode might require much less validation than something in “Approved” mode.

  71. Steve

    @Fregas – you’re on the right lines! The scenario you described is exactly why validation (and business rules in general) *should* be in the domain model. See my follow-up post for more details: http://blog.codeville.net/2008/09/08/thoughts-on-validation-in-aspnet-mvc-applications/

  72. Mahesh

    ya its very usefull… to the validation

  73. Mose

    As a former user of Castle validator, I find this really useful.

    But as a new user of Entity Framework, I think it’s not an ultimate way of validation as the properties of my model are managed by a code generator (I cannot put attributes on them).

    And a as a purist of development, I think the validation should NOT be in the model, because :
    1) it’s already in it :
    If your field is a DateTime then it’s a non-empty DateTime. If your field is a DateTime? then it’s a potential empty DateTime.
    The only problem I can see here is the “string” instances that can always be null. The framework is lacking a “non empty string” type (and as you cannot inherit of string, there is no trivial solution)

    2) If you have a nullable field, depending on the form (think of a workflow) you will want it to be empty or not. Using attributes in the model puts an absolute rule where I would need a relative one.

    conclusion => In my sense, the controlleur is the one that should trigger validation, and the view needs to be part of the process, to display it in the right way (and to bypass default generated validation display if needed)

  74. Mose

    Well… cannot edit my comment so just let me add some details to prevent an angry attack :

    * Steve, I’m ok with almost 80% of your thaught concerning validation : the model should be able to validate itself and throw exceptions that the UI has to handle and display.

    * But I really think that validation don’t have to be be managed only in the Model. I really need to have a validation layer in the controller, exception bubbled up from the Model are not enought. The main reason is the need of custom client validation. With ‘custom’ I mean ‘not automatically generated’ : with custom display and custom language

    We can argue a lot on that subject, it’s a question of development philosophy and of ‘what-component-cares-of-what-concern’ (dunno the appropriate term, english is not my native language).

    Maybe validation should be modelized and handled in layers, depending on the issues and the customer needs. I’ll really think about that.

    Whatever : your implementation of validation is a great stuff !
    Keep going and happy new year.

  75. bhupendran

    Look Great but i m getting lot of error while running ur project. Please post a good example.So that all can understand .

  76. Steve

    @bhupendran – this post was written way back in April 2008, so I wouldn’t be surprised if it doesn’t immediately work with the latest version of ASP.NET MVC. Have a look at my more recent work on xVal instead: http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/

  77. Marko

    Hello Steve,

    just ran into this and it is very cool but I do have a problem when I try to set up the same example. Here is the error message I get:

    error CS0012: The type ‘System.Web.Mvc.HtmlHelper’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’.

    The error happens when I enter the following line into the view code:

    When I look at my webconfig I do have System.Web.Mvc such as:

    the only difference being the PublicKeyToken value… Is this just an issue with assebly version and do you have any idea how to fix it?

    Thanks in advance!

  78. Marko

    with regards to my previous post the line that’s causing the issue is:

    Html.ErrorSummary(“Sorry, there was a problem”, (string[])TempData["errors"])

  79. tom

    Hello,

    Its a very nice aproach, i’m keen on using it! However, I can’t get the client validation to work. I have the same problem Marko ran into… Is there already a solution for this problem? Or is there something i’m missing? I tried adding the System.Web.Mvc reference on the page, but this gave no result, the error still exists :(

    Thx for the help,

    Regards,
    Tom

  80. Marko, Tom – this example code is for ASP.NET MVC only. You can’t use it with WebForms. Sorry.

  81. It takes a thief to catch a thief

  82. vaibhav patel

    Hello Mate !,

    how to use document validation in file upload control ?

    thanks