ASP.NET MVC 2: Model Validation

[In addition to blogging, I am also now using Twitter for quick updates and to share links. Follow me at: twitter.com/scottgu]

This is the second in a series of blog posts I’m doing on the upcoming ASP.NET MVC 2 release.  This blog post covers some of the validation improvements coming with ASP.NET MVC 2.

ASP.NET MVC 2 Validation

Validating user-input and enforcing business rules/logic is a core requirement of most web applications.  ASP.NET MVC 2 includes a bunch of new features that make validating user input and enforcing validation logic on models/viewmodels significantly easier.  These features are designed so that the validation logic is always enforced on the server, and can optionally also be enforced on the client via JavaScript.  The validation infrastructure and features in ASP.NET MVC 2 are designed so that:

1) Developers can easily take advantage of the DataAnnotation validation support built-into the .NET Framework.  DataAnnotations provide a really easy way to declaratively add validation rules to objects and properties with minimal code.   

2) Developers can optionally integrate either their own validation engine, or take advantage of existing validation frameworks like Castle Validator or the EntLib Validation Library. ASP.NET MVC 2’s validation features are designed to make it easy to plug-in any type of validation architecture – while still taking advantage of the new ASP.NET MVC 2 validation infrastructure (including client-side validation, model binding validation, etc).

This means that enabling validation is really easy for common application scenarios, while at the same time still remaining very flexible for more advanced ones.

Enabling Validation with ASP.NET MVC 2 and DataAnnotations

Let’s walkthrough a simple CRUD scenario with ASP.NET MVC 2 that takes advantage of the new built-in DataAnnotation validation support.  Specifically, let’s implement a “Create” form that enables a user to enter friend data:

image

We want to ensure that the information entered is valid before saving it in a database – and display appropriate error messages if it isn’t:

image

We want to enable this validation to occur on both the server and on the client (via JavaScript).  We also want to ensure that our code maintains the DRY principle (“don’t repeat yourself”) – meaning that we should only apply the validation rules in one place, and then have all our controllers, actions and views honor it.

Below I’m going to be using VS 2010 to implement the above scenario using ASP.NET MVC 2.  You could also implement the exact same scenario using VS 2008 and ASP.NET MVC 2 as well.

Step 1: Implementing a FriendsController (with no validation to begin with)

We’ll begin by adding a simple “Person” class to a new ASP.NET MVC 2 project that looks like below:

image

It has four properties (implemented using C#’s automatic property support, which VB in VS 2010 now supports too – woot!).

We’ll then add a “FriendsController” controller class to our project that exposes two “Create” action methods.  The first action method is called when an HTTP-GET request comes for the /Friends/Create URL.  It will display a blank form for entering person data.  The second action method is called when an HTTP-POST request comes for the /Friends/Create URL.  It maps the posted form input to a Person object, verifies that no binding errors occurred, and if it is valid will eventually save it to a database (we’ll implement the DB work later in this tutorial).  If the posted form input is invalid, the action method redisplays the form with errors:

image

After we’ve implemented our controller, we can right-click within one of its action methods and choose the “Add View” command within Visual Studio – which will bring up the “Add View” dialog.  We’ll choose to scaffold a “Create” view that is passed a Person object:

image

Visual Studio will then generate a scaffolded Create.aspx view file for us under the \Views\Friends\ directory of our project.  Notice below how it takes advantage of the new strongly-typed HTML helpers in ASP.NET MVC 2 (enabling better intellisense and compile time checking support):

image

And now when we run the application and hit the /Friends/Create URL we’ll get a blank form that we can enter data into:

image

Because we have not implemented any validation within the application, though, nothing prevents us from entering bogus input within the form and posting it to the server.

Step 2: Enabling Validation using DataAnnotations

Let’s now update our application to enforce some basic input validation rules.  We’ll implement these rules on our Person model object – and not within our Controller or our View.  The benefit of implementing the rules within our Person object is that this will ensure that the validation will be enforced via any scenario within our application that uses the Person object (for example: if we later added an edit scenario).  This will help ensure that we keep our code DRY and avoid repeating rules in multiple places.

ASP.NET MVC 2 enables developers to easily add declarative validation attributes to model or viewmodel classes, and then have those validation rules automatically be enforced whenever ASP.NET MVC performs model binding operations within an application.  To see this in action, let’s update our Person class to have a few validation attributes on it.  To do this we’ll add a “using” statement for the “System.ComponentModel.DataAnnotations” namespace to the top of the file – and then decorate the Person properties with [Required], [StringLength], [Range], and [RegularExpression] validation attributes (which are all implemented within that namespace):

image

Note: Above we are explicitly specifying error messages as strings. Alternatively you can define them within resource files and optionally localize them depending on the language/culture of the incoming user.  You can learn more about how to localize validation error messages here.

Now that we’ve added the validation attributes to our Person class, let’s re-run our application and see what happens when we enter bogus values and post them back to the server:

image

Notice above how our application now has a decent error experience.  The text elements with the invalid input are highlighted in red, and the validation error messages we specified are displayed to the end user about them.  The form is also preserving the input data the user originally entered – so that they don't have to refill anything.  How though, you might ask, did this happen? 

To understand this behavior, let’s look at the Create action method that handles the POST scenario for our form:

image

When our HTML form is posted back to the server, the above method will be called.  Because the action method accepts a “Person” object as a parameter, ASP.NET MVC will create a Person object and automatically map the incoming form input values to it.  As part of this process, it will also check to see whether the DataAnnotation validation attributes for the Person object are valid.  If everything is valid, then the ModelState.IsValid check within our code will return true – in which case we will (eventually) save the Person to a database and then redirect back to the home-page. 

If there are any validation errors on the Person object, though, our action method redisplays the form with the invalid Person.  This is done via the last line of code in the code snippet above.

The error messages are then displayed within our view because our Create form has <%= Html.ValidationMessageFor() %> helper method calls next to each <%= Html.TextBoxFor() %> helper.  The Html.ValidationMessageFor() helper will output the appropriate error message for any invalid model property passed to the view:

image

The nice thing about this pattern/approach is that it is pretty easy to setup – and it then allows us to easily add or change validation rules on our Person class without having to change any code within our controllers or views.  This ability to specify the validation rules one place and have it be honored and respected everywhere allows us to rapidly evolve our application and rules with a minimum amount of effort and keep our code very DRY.

Step 3: Enabling Client-side Validation

Our application currently only performs server-side validation – which means that our end users will need to perform a form submit to the server before they’ll see any validation error messages.

One of the cool things about ASP.NET MVC 2’s validation architecture is that it supports both server-side and client-side validation.  To enable this, all we need to do is to add two JavaScript references to our view, and write one line of code:

image

When we add these three lines, ASP.NET MVC 2 will use the validation meta-data we’ve added to our Person class and wire-up client-side JavaScript validation logic for us. This means that users will get immediate validation errors when they tab out of an input element that is invalid. 

To see the client-side JavaScript support in action for our friends application, let’s rerun the application and fill in the first three textboxes with legal values – and then try and click “Create”.  Notice how we’ll get an immediate error message for our missing value without having to hit the server:

image

If we enter some text that is not a legal email the error message will immediately change from “Email Required” to “Not a valid email” (which are the error messages we specified when we added the rules to our Person class):

image

When we enter a legal email the error message will immediately disappear and the textbox background color will go back to its normal state:

image

The nice thing is that we did not have to write any custom JavaScript of our own to enable the above validation logic.  Our validation code is also still very DRY- we can specify the rules in one place and have them be enforced across all across the application – and on both the client and server.

Note that for security reasons the server-side validation rules always execute even if you have the client-side support enabled.  This prevents hackers from trying to spoof your server and circumvent the client-side rules.

The client-side JavaScript validation support in ASP.NET MVC 2 can work with any validation framework/engine you use with ASP.NET MVC.  It does not require that you use the DataAnnotation validation approach – all of the infrastructure works independent of DataAnnotations and can work with Castle Validator, the EntLib Validation Block, or any custom validation solution you choose to use.

If you don’t want to use our client-side JavaScript files, you can also substitute in the jQuery validation plugin and use that library instead.  The ASP.NET MVC Futures download will include support for enable jQuery validation against the ASP.NET MVC 2 server-side validation framework as well.

Step 4: Creating a Custom [Email] Validation Attribute

The System.ComponentModel.DataAnnotations namespace within the .NET Framework includes a number of built-in validation attributes that you can use.  We’ve used 4 different ones in the sample above - [Required], [StringLength], [Range], and [RegularExpression].

You can also optionally define your own custom validation attributes and use them as well.  You can define completely custom attributes by deriving from the ValidationAttribute base class within the System.ComponentModel.DataAnnotations namespace.  Alternatively, you can choose to derive from any of the existing validation attributes if you want to simply extend their base functionality. 

For example, to help clean up the code within our Person class we might want to create a new [Email] validation attribute that encapsulates the regular expression to check for valid emails.  To do this we can simply derive it from the RegularExpression base class like so, and call the RegularExpression’s base constructor with the appropriate email regex:

image

We can then update our Person class to use our new [Email] validation attribute in place of the previous regular expression we used before – which makes the code more clean and encapsulated:

image

When creating custom validation attributes you can specify validation logic that runs both on the server and on the client via JavaScript.

In addition to creating validation attributes that apply to individual properties on an object, you can also apply validation attributes at the class level – which allows you to perform validation logic across multiple properties within an object.  For an example of this in action, you can review the “PropertiesMustMatchAttribute” custom attribute that is included in the AccountModels.cs/vb file within the default ASP.NET MVC 2 application project template (just do a File->New ASP.NET MVC 2 Web Project within VS 2010 and look for this class). 

Step 5: Persisting to a Database

Let’s now implement the logic necessary to save our friends to a database. 

image 

Right now we are simply working against a plain-old C# class (sometimes referred to as a “POCO” class - “plain old CLR (or C#) object”).  One approach we could use would be to write some separate persistence code that maps this existing class we’ve already written to a database. Object relational mapping (ORM) solutions like NHibernate support this POCO / PI style of mapping today very well.  The ADO.NET Entity Framework (EF) that ships with .NET 4 will also support POCO / PI mapping, and like NHibernate will also optionally enable the ability to define persistence mappings in a “code only” way (no mapping file or designers required). 

If our Person object was mapped to a database in this way then we wouldn’t need to make any changes to our Person class or to any of our validation rules – it would continue to work just fine. 

But what if we are using a graphical tool for our ORM mappings?

Many developers using Visual Studio today don’t write their own ORM mapping/persistence logic – and instead use the built-in designers within Visual Studio to help manage this.

One question that often comes up when using DataAnnotations (or any other form of attribute based validation) is “how do you apply them when the model object you are working with is created/maintained by a GUI designer”.  For example, what if instead of having a POCO style Person class like we’ve been using so far, we instead defined/maintained our Person class within Visual Studio via a GUI mapping tool like the LINQ to SQL or ADO.NET EF designer:

image

Above is a screen-shot that shows a Person class defined using the ADO.NET EF designer in VS 2010.  The window at the top defines the Person class, the window at the bottom shows the mapping editor for how its properties map to/from a “People” table within a database.  When you click save on the designer it automatically generates a Person class for you within your project.  This is great, except that every time you make a change and hit save it will re-generate the Person class – which would cause any validation attribute declarations you make on it to be lost.

One way you can apply additional attribute-based meta-data (like validation attributes) to a class that is auto-generated/maintained by a VS designer is to employ a technique we call “buddy classes”.  Basically you create a separate class that contains your validation attributes and meta-data, and then link it to the class generated by the designer by applying a “MetadataType” attribute to a partial class that is compiled with the tool-generated class.  For example, if we wanted to apply the validation rules we used earlier to a Person class maintained by a LINQ to SQL or ADO.NET EF designer we could update our validation code to instead live in a separate “Person_Validation” class that is linked to the “Person” class created by VS using the code below:

image

The above approach is not as elegant as a pure POCO approach – but has the benefit of working with pretty much any tool or designer-generated code within Visual Studio. 

Last Step – Saving the Friend to the Database

Our last step – regardless of whether we use a POCO or tool-generated Person class – will be to save our valid friends into the database. 

Doing that simply requires us to replace the “Todo” placeholder statement within our FriendsController class with 3 lines of code that saves the new friend to a database.  Below is the complete code for the entire FriendsController class - when using ADO.NET EF to do the database persistence for us:

image

And now when we visit the /Friends/Create URL we can easily add new People to our friends database:

image

Validation for all the data is enforced on both the client and server.  We can easily add/modify/delete validation rules in one place, and have those rules be enforced by all controllers and views across our application.

Summary

ASP.NET MVC 2 makes it much easier to integrate validation into web applications. It promotes a model-based validation approach that enables you to keep your applications very DRY, and helps ensure that validation rules are enforced consistently throughout an application.  The built-in DataAnnotations support within ASP.NET MVC 2 makes supporting common validation scenarios really easy out of the box.  The extensibility support within the ASP.NET MVC 2 validation infrastructure then enables you to support a wide variety of more advanced validation scenarios – and plugin any existing or custom validation framework/engine.

Hope this helps,

Scott

110 Comments

  • Looks great! Just implemented this on a big project at work using xVal.

    Looking forward to read more about MVC 2 :-)

  • Scott

    Fantastic stuff, can't wait until the RTM is coming!

    I was trying to do some custom validators like your email example (but not reusing the regex base validator).
    How would I emit Javascript to the client in order to get custom client side validation as well?
    Of course I could put it directly into the view, but isn't there some way to have it rendered automatically

    Best Regards
    -Kay

  • How easy is this to customize so you could use something like the JQuery Validation plugin?

  • Good article as usual, but why is there no sourcecode download ?
    And sourcecode in a image looks nice, but NO COPY / PASTE!

  • Should you not mention Subsonic as well regarding POCO.

    Looks great though!

  • What about string minimum length validation?

  • How do the server side validations work with ajax post? i.e, how can i send the validation errors back to the client?

  • Very good!
    However, for custom validation that does not belong to objects, but rather to the database ( such as the email of a person is unique), o you recommend using IDataErrorInfo ?

  • @pod.Omen :
    You can use RangeAttribute( sorry for my previous comment)

  • What about if you want multiple forms on the same page, each with their own submit button? For instance, a Login form and a Sign-up form on the same page, like you see in e-commerce websites.

  • Is there going to be any support for tokenized resource strings similar to the Validation Application Block?

    Lets say I have 2 string properties...

    public string StreetAddress1 {get; set;}
    public string StreetAddress1 {get; set;}

    ... and I want to validate the max string length. I want to add this attribute to both of them...

    [StringLength(50, ErrorMessageResourceName="InvalidStringLength", ErrorMessageResourceType=typeof(ValidationMessages)]

    ... And the Resource string should look like this...

    "{1} property must have fewer characters than {2}"

    Now I can re-use the resource strings on dozens of different properties. The VAB did this so its not exactly new technology for Microsoft.

  • I'd like to see this implemented using JQuery instead of MicrosoftAjax.

  • @pod.Omen

    I don't know about other approaches, but minimum string length could be easily done as a regular expression.

  • Hi Scott,

    In string "We’ve used 4 different ones in the sample above - [Required], [StringLength], [Required], and [RegularExpression]." may be the third attribute is "[Range]"?

  • One of the BIG problems with validation is required field support not working as it should. Turn off client validation in your code above (like client disabled javascript). Then do not fill out ANYTHING on your form and hit submit. Model.IsValid will return true and you will add an empty person to your table - probably resulting in a database error.

    In addition, an article on adding support for jquery validation and on adding custom validations to support both client and server would be a nice addition to your series. :-)

  • Great,when will it support sub controller?

  • Thanks for the nice post and your hard work.

  • Is it possible to have validation based on more than one field

    e.g. if "Salary" is "> £50,000" then the value entered in the "minimum contribution" field must be greater than 5%

    ??

  • Good post. Noticed in your listing of validation attributes that required appears twice instead of using range.

  • Great timing on the article, but I also agree with ignatandrei. How do you extend this model for more extensive validation that needs info from a DB?

  • Is it possible to use DataAnnotations in Windows Forms?

  • Thanks for this series. I think it really ROCKS...

    Regards

  • Writing custom JavaScript validation code for custom validation would be interesting...

  • When you get to your article on AsyncController (hopefully soon :) ) can you please go over how to implement validation in that scenario?

  • Hello Scott,

    Thanks for this post.

    In addition to WayneBrantley's comment (http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx#7311799)...

    Does the Required attribute work as expected when there's no "key" in the POST data for that field? For example, it should add an error for LastName when POST data is "FirsName=f&Age=30&Email=a@a.com".
    Please see this SO question for more details.
    http://stackoverflow.com/questions/784960/

    Thanks again

  • Scott, I've seen some debate about the following and not sure which is better: If you're using a ViewModel class where would you put your validation annotations, in Person or PersonViewModel?

    Another question is, could you have a post about ViewModels and what are the possible approaches, it seems to be used by everyone and yet we don't see it in the default MVC templates or being discussed on "official" blogs a lot?

    As usual, thanks for all the info you're sharing!

  • @Timur: It's using "System.ComponentModel.DataAnnotations" so nothing web-specific about it so definitely can be used with WinForm apps.

  • So yes MVC 2 really rocks ...
    PS : What about validation base on 2 or more properties ?
    Assume we have 2 properties StartTime and EndTime and we want ensure EndTime is always after StartTime. How can we implement this by Data-annotations?
    Thanks in advance .

  • So yes MVC 2 really rocks ...
    PS : What about validation base on 2 or more properties ?
    Assume we have 2 properties StartTime and EndTime and we want ensure EndTime is always after StartTime. How can we implement this by Data-annotations?
    Thanks in advance .

  • Great post...

    Regards.

  • For all those who asked questions about multiproperty validation using custom data annotation validators and also asked about the min string length validator, you can easily create your own custom validator by deriving from ValidationAttribute class. There are two examples included in the asp.net mvc 2 default project template in the AccountModels.cs file. One is the multproperty validator example custom attribute named PropertiesMustMatchAttribute that you apply at the class level to your model and the other is the custom ValidatePasswordLengthAttribute which is a property level custom validator that you apply to the properties of your model.
    You can use the ValidatePasswordLengthAttribute implementation as an example of making your own min string length validator and you can use the PropertiesMustMatchAttribute implementation as an example of how to do muliproperty validators (note this is done by making the validator a class level validator by using AttributeUsage = AttributeTargets.Class)

    Hope this helps

  • Could you give an example how to persist the Person object elegantly into database without using ORM?

  • Thanks Scott!

    Great series - I like the ASP:NET MVC framework more each day. The way is supposed to be programmed, if you ask me.

    Keep 'em coming!

  • @Kay,

    >>>>>>>> Fantastic stuff, can't wait until the RTM is coming!

    I was trying to do some custom validators like your email example (but not reusing the regex base validator). How would I emit Javascript to the client in order to get custom client side validation as well? Of course I could put it directly into the view, but isn't there some way to have it rendered automatically

    We should hopefully get some more samples up soon that show how best to do this. Phil Haack has a sample from November that shows how to use it with the ASP.NET MVC Beta that might help: http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx I'm not sure if some details have changed for the ASP.NET MVC RC since that article was posted - but hopefully that provides a good way to get started right now.

    Hope this helps,

    Scott

  • @docluv,

    >>>>>>>> How easy is this to customize so you could use something like the JQuery Validation plugin?

    Pretty straight-forward actually - the ASP.NET MVC validation support flows validation meta-data that can be used by any client-side JavaScript framework. We'll actually ship support within the ASP.NET MVC futures download that provides direct support for the jQuery Validation plugin.

    Hope this helps,

    Scott

  • @Martino,

    >>>>>>>> Good article as usual, but why is there no sourcecode download ?

    I actually wrote the code using a recent VS 2010 build that isn't public yet - so I couldn't share the code since the code above requires the ASP.NET MVC RC (which currently only works with VS 2008 publicaly). I'll be posting code in the future though. Hopefully it isn't too much code to type though!

    Scott

  • @ j.channon

    >>>>>>>> Should you not mention Subsonic as well regarding POCO.

    Yep - it works great with Subsonic too!

    Thanks,

    Scott

  • @pod.Omen,

    >>>>>>>> What about string minimum length validation?

    The [StringLength] attribute doesn't support min length it looks like (which I think is a bit odd). What you can alternatively do is either use the regular expression attribute to enforce this, or create your own custom attribute.

    Note that [Required] will enforce that the string must have some value - which handles the common string case where it must be greater than 0.

    Hope this helps,

    Scott

  • @Ke,

    >>>>>>>>> How do the server side validations work with ajax post? i.e, how can i send the validation errors back to the client?

    Yes - you can handle this. I believe Phil Haack has it on his list to blog about soon.

    Hope this helps,

    Scott

  • @ignatandrei

    >>>>>>> However, for custom validation that does not belong to objects, but rather to the database ( such as the email of a person is unique), o you recommend using IDataErrorInfo ?

    You could use IDataErrorInfo for this - although I might actually just create a [UniqueEmail] attribute and have it hit the database to enforce the uniqueness. I personally think that is a little cleaner.

    Hope this helps,

    Scott

  • @Dominic,

    >>>>>>>>> What about if you want multiple forms on the same page, each with their own submit button? For instance, a Login form and a Sign-up form on the same page, like you see in e-commerce websites.

    Yes - this is fully supported. The validation rules wired up on the client-side would only be enforced if the particular form that is posted is submitted (meaning a login form wouldn't cause other forms on the page to execute their validations).

    Hope this helps,

    Scott

  • @Dan,

    >>>>>>> Is there going to be any support for tokenized resource strings similar to the Validation Application Block?

    Unfortunately I don't think the built-in [StringLength] validator supports this (this ships separate from ASP.NET MVC - so we can't change it as part of the ASP.NET MVC 2 release). However, you could create your own custom validator (either by sub-classing it or deriving from ValidationAttribute) and add this support foe the error message.

    Hope this helps,

    Scott

  • @nick4eva, @Josh

    >>>>>>>> In string "We’ve used 4 different ones in the sample above - [Required], [StringLength], [Required], and [RegularExpression]." may be the third attribute is "[Range]"?

    I apparently forgot to validate my text.. ;-) Just fixed it.

    Thanks,

    Scott

  • @marek,

    >>>>>>>> One question - what is the best practise to localize the validation messages?

    Here is a post that describes how to do this: http://haacked.com/archive/2009/12/07/localizing-aspnetmvc-validation.aspx

    Hope this helps,

    Scott

  • @Wayne,

    >>>>>>>> One of the BIG problems with validation is required field support not working as it should. Turn off client validation in your code above (like client disabled javascript). Then do not fill out ANYTHING on your form and hit submit. Model.IsValid will return true and you will add an empty person to your table - probably resulting in a database error.

    Can you send me email (scottgu@microsoft.com) about this issue? I'd love to have the team take a look at it.

    Thanks,

    Scott

  • @Webdiver,

    >>>>>>>>>> Great,when will it support sub controller?

    I'll cover Areas and Html.RenderAction (two new features in ASP.NET MVC 2) later in this blog post series.

    Hope this helps,

    Scott

  • @chris,

    >>>>>>> Is it possible to have validation based on more than one field e.g. if "Salary" is "> £50,000" then the value entered in the "minimum contribution" field must be greater than 5%

    Yes - In addition to creating validation attributes that apply to individual properties on an object, you can also apply validation attributes at the class level – which allows you to perform validation logic across multiple properties within an object. For an example of this in action, you can review the “PropertiesMustMatchAttribute” custom attribute that is included in the AccountModels.cs/vb file within the default ASP.NET MVC 2 application project template (just do a File->New ASP.NET MVC 2 Web Project within VS 2010 and look for this class).

    Hope this helps,

    Scott

  • @Jamie,

    >>>>>>>>> When you get to your article on AsyncController (hopefully soon :) ) can you please go over how to implement validation in that scenario?

    The good news is that this validation works just fine with AsyncControllers too :-)

    Hope this helps,

    Scott

  • @Ivan,

    >>>>>>>> Scott, I've seen some debate about the following and not sure which is better: If you're using a ViewModel class where would you put your validation annotations, in Person or PersonViewModel? Another question is, could you have a post about ViewModels and what are the possible approaches, it seems to be used by everyone and yet we don't see it in the default MVC templates or being discussed on "official" blogs a lot?

    That is a good topic. We are working on an upcoming ASP.NET MVC 2 end to end app tutorial where we'll provide more guidance on using a viewmodel based approach.

    With regard to validation - in general "it depends". From a DRY perspective it would be ideal if you could put the validation on the model and have your viewmodels reflect/respect that automatically. Having said that, sometimes the shape of ViewModels look differently than Models - in which case having validation automatically transfer between models/viewmodels might be different (for example: if you flatten fields or expose them differently). We'll try and get more guidance out there that show off how to handle different scenarios.

    Hope this helps,

    Scott

  • @ali62b,

    >>>>>>>> Assume we have 2 properties StartTime and EndTime and we want ensure EndTime is always after StartTime. How can we implement this by Data-annotations?

    Yes - In addition to creating validation attributes that apply to individual properties on an object, you can also apply validation attributes at the class level – which allows you to perform validation logic across multiple properties within an object. For an example of this in action, you can review the “PropertiesMustMatchAttribute” custom attribute that is included in the AccountModels.cs/vb file within the default ASP.NET MVC 2 application project template (just do a File->New ASP.NET MVC 2 Web Project within VS 2010 and look for this class).

    Hope this helps,

    Scott

  • @bangoker,

    >>>>>>>>> What would be the best approach if you have a View that contains elements from several DB entities (let say Persons and Pets)? I usually follow patterns 2 and 3 that Steve Michelotti mentions in this blog: geekswithblogs.net/.../asp.net-mvc-view-model-patterns.aspx, where I'd either have a viewmodel class that contains the entity classes as properties (public Person Friend{get;set;} public Animal Pet..) or when i just need a few fields from the class, I would have them directly in the ViewModel, and then use a mapper to map them into the actual entity class. How would you validate then? Would you put the validationData just in the ViewModel, or in the View Model AND Entity Classes???

    If your ViewModel's simply expose your model objects as properties - then you can add the DataAnnotations to your model objects and things will just work. If you flatten your ViewModels so that they expose custom scalar properties (and then internally map them to Model objects) then you might need to either duplicate your DataAnnotations (or write new ones that better represent your ViewModel properties) or alternatively you could write a custom validation attribute that you apply to your ViewModel (as a class-level validation attribute) that then honors the validation logic on the Model object.

    Hope this helps,

    Scott

  • Thanks Areg that was very helpful. Cheers
    PS: I wrote this (helpful for other have same problem):
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public sealed class SecondPropertyShouldGreater : ValidationAttribute
    {
    private const string _defaultErrorMessage = "'{0}' should before '{1}' .";

    private readonly object _typeId = new object();

    public SecondPropertyShouldGreater(String firstProperty, String secondProperty)
    : base(_defaultErrorMessage)
    {
    FirstProperty = firstProperty;
    SecondProperty = secondProperty;
    }

    public String FirstProperty
    {
    get;
    private set;
    }

    public String SecondProperty
    {
    get;
    private set;
    }

    public override object TypeId
    {
    get
    {
    return _typeId;
    }
    }

    public override bool IsValid(object value)
    {
    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
    object firstValue = properties.Find(FirstProperty, true /* ignoreCase */).GetValue(value);
    object secondValue = properties.Find(SecondProperty, true /* ignoreCase */).GetValue(value);
    return ((DateTime)firstValue <(DateTime)secondValue);
    }

    public override string FormatErrorMessage(string name)
    {
    return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
    FirstProperty, SecondProperty);
    }
    }

  • It was helpful indeed, I didn't know about class level validation attributes. Good point.

  • PS:I put [SecondPropertyShouldGreater("StartTime", "EndTime")] above my class (for other have the same problem):
    [SecondPropertyShouldGreater("StartTime", "EndTime")]
    public class Session
    {
    public int ID { get; set; }

    public DateTime StartTime { get; set; }


    public DateTime EndTime { get; set; }

    }

  • @Dan,

    Check out the FormatErrorMessage method on the StringLengthAttribute. It returns a tokenized string that uses the property's name as the first param {0}, and the maximum length as param {1}.

    An example of the string you would use for the resource file would be like: "The field {0} must be a string with a maximum length of {1}." This is what the attribute uses by default.

    So if your FirstName property had a [StringLength(5)] attribute applied, and was failing validation, you would see the message: "The field FirstName must be a string with a maximum length of 5."

    To customize the error message with your own, you would apply the attribute like this: [Required] [StringLength(5, ErrorMessageResourceName = "YourCustomStringLengthError", ErrorMessageResourceType = typeof(Resources))]

    The YourCustomStringLengthError resource string could be anything you want, just include the {0} and {1} where you want the property name and maximum length to show up.

    All of the ValidationAttributes have this FormatErrorMessage method. To do the same thing with the RequiredAttribute, you would only need to have the first param in your resource string.

  • Great work obviously :) however, I am wondering whether anyone else is feeling uneasy with the idea of "polluting" the domain with ui-related strings/messages? Just wondering :)

  • Thank you Scott!

    Such a great guy to answer to all the posts so quickly!

  • Nice work.
    I'm very new to MVC sorry... but where's the AddToPeople() function definition?

  • How do you handle "virtual properties", for instance, if you wanted to add a "Confirm Email" field to the form? This field wouldn't be part of the model, it would purely be for data entry validation. It would be excellent to see how an example of this works?

    Cheers,

    John

  • I cant find the "PropertiesMustMatchAttribute" anywhere. I am running Visual Studio 2010 Beta 2 and have tried creating a new MVC 2 web application as you write, but it is not there.

    Also i have searched the MVC 2 source code and the MVC futures download and it is not there either.

    Could someone post the code for this attribute ?

  • @MartinF
    It is part of the VS2008 version of MVC2 not yet in 2010.

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public sealed class PropertiesMustMatchAttribute : ValidationAttribute
    {
    private const string _defaultErrorMessage = "'{0}' and '{1}' do not match.";

    private readonly object _typeId = new object();

    public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty)
    : base(_defaultErrorMessage)
    {
    OriginalProperty = originalProperty;
    ConfirmProperty = confirmProperty;
    }

    public string ConfirmProperty
    {
    get;
    private set;
    }

    public string OriginalProperty
    {
    get;
    private set;
    }

    public override object TypeId
    {
    get
    {
    return _typeId;
    }
    }

    public override string FormatErrorMessage(string name)
    {
    return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
    OriginalProperty, ConfirmProperty);
    }

    public override bool IsValid(object value)
    {
    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
    object originalValue = properties.Find(OriginalProperty, true ).GetValue(value);
    object confirmValue = properties.Find(ConfirmProperty, true ).GetValue(value);
    return Object.Equals(originalValue, confirmValue);
    }
    }

  • Thanks for the post! Is there a out of the box solution for displaying a validation summary without a post? Thanks!

  • What if you add a DateTime (non-nullable) to Person called BirthDate for example. In display and editor mode you want to use m.BirthDate) %> but display an empty textbox in case BirthDate has it's default value (which is DateTime.MinValue if I am not mistaken, since it is not nullable). I've looked everywhere, but can't seem to find an attribute that does that. Is there an attribute I've missed?

    E.G. (which does not exist)
    [DisplayFormat(DefaultValueText = "")]
    public DateTime BirthDate { get; set; }

  • Hi Scott,

    I noticed the validation only works for creation, all of my validations are not fired on the client when in Edit mode. Would this be implemented on Edit also or just for creation?

    Cheers,
    Jonel

  • What if we are sending Person as a data contract to client via WCF web service. Would data annotation still work? Would it work with non-.net clients.

  • Thanks for the insightful article.

    I was wondering how you can implement remote client-side validation in ASP.NET MVC 2. In other words, how do you implement client-side validation for rules that can only be validated on the server (for errors such as "this e-mail address is already taken").

    I wrote an article how to implement this with xVal and jquery.validate so that you don't need any client-side code and I am wondering if a similar approach could be used with ASP.NET MVC 2's validation framework. I guess I would have to implement a remote validator on the client-side. Is there any extensibility mechanism built into the client-side code that would facilitate this? Or perhaps there already is a remote validation rule?

  • I forgot to link the article I was referring to in my previous comment:

    ASP.NET MVC client-side form validation made easy

  • Hi,
    Is it possible to use Data validation if your business layer is exposed using web services for exemple ?
    Regards

  • Hey Scott, Great Tutorial, Thanks
    Question:
    How does your Strongly Typed View (MVCValidationSample.Models.Person) map to the Person's Entity Framework class?

    I mean this following line, blew my mind:
    friends.AddToPeople(friendToCreate);
    Those are different types, although they have the same properties, there's two different classes.

    Thanks in advance,
    Gabriel

  • Hi Scott, thanks for the post.

    I have two questions:

    1. The first one is about ASP.NET MVC 2 validations. Is there native support for validation messages internationalization? Or the validation messages can only be defined statically and though the validation messages cannot be based on resource files?

    2. The second one is about Entity Framework. I have some complex stored procedures in the database that I need to call from mu WebApp. The only problem is that I think I can't access them through the EntityModel. Is there any way? The only way that I have now is to create a linq to sql dbml file and import the stored procedures to execute them. But that way I always need to intanciate a EntityModel and a LinqToSql context.

  • Very nice article sir.

    Thanks,
    Thani

  • Great article.
    Thanks Scott

  • This sounds interesting, but this method only allows validating fields individuly. I am hoping it can provide a correlated validation at the class level which will be executed only after all fields are valid. By doing so, it can accomondate more business rules. Otherwise, developers may still have to do the validation in the controller.

  • I noticed when you do HtmlHelper.LabelFor(x => x.FirstName) the Label text is "FirstName". How would we get the text to be "First Name"? Is there an attribute to specify the Label text?

  • I too wish that model binder would validate the whole entity instead of just the posted data. An example is an int property on a "model" with Range validation between 10 and 20. And if this field is not present in the client form (for some reason), it is not posted from the client to the server, then it is not validated, and you can (if you don't have a constraint in the datastore, i.e.) have wrong data in the datastore.

  • Scott,

    Can you point to an example showing the proper way to do this type of validation against a DropDownList/SelectList?

    Ryan

  • Hi Scott,
    I had a little problem when I userd mvc2,I can`t fint Html.TextBoxFor.it was still Html.TextBox. can you show why? I userd vs2010 beta 2. Thank you very much~

  • I have been looking for a way to make the Range validator take a dynamic maximum without having to make a custom validator. If I were to make a view to add students to a class then my dynamic range validator needs to have a maximum set when the view is rendered. As the class fills up the range maximum goes down. Is that possible?

  • I am using MVC 2 and applying client side validation, however I want to be able to validate a form BEFORE it is submitted is there any way to call validate rather than let the form submission call it?

    My scenario is:
    - Fill in form, click next
    - *validate the form*
    - Display a confirmation message
    - Submit the form.

  • @Josh Kodroff - use DisplayName attribute

  • What about multi-language support for the error-messages? (as well in JavaScript as on the Server) .. how does that work?

  • Hello Scott,
    You said that for custom validation such as Unique email - that is enforced by an index in the database - you may create an "[UniqueEmail] attribute and have it hit the database to enforce the uniqueness. "
    How do you handle concurrency ? ( e.g. first user post email aaa@aaa.com - UniqueEmail verifies - is unique, second user post email aaa@aaa.com - UniqueEmail verifies - is unique - and the one of them is getting an error from the index)

    I ask this because I want to get rid of IDataErrorInfo - that is pretty long to implement...

    Thank you for your answer!

  • This doesn't seem to be working for me when my dbml and partial classes are in a separate project than the MVC project (DAL project). When I rip the code out of the DAL project and put it directly into my MVC project under "Models" it works. Any ideas?

  • how to implement compare attribute?

  • Hi Scott,

    Thanks, great post!

    Question: How do we use Client Validation when using a List in our view data class?

    Using your same example, I created a class with a List, which I use as the strongly-typed view data class.

    public class FriendsViewData
    {
    public List people { get; set; }
    }

    In the View I put a for loop around the fieldset and referenced the properties like this:


    item.FirstName) %>


    model.people[i].FirstName) %>
    model.people[i].FirstName) %>


    Looking at the generated name and id attributes, it looks like Client Validation wasn't built to handle Lists... is this the case or am I missing something?

    Any help appreciated! I'm actually need this on my current project.
    Thanks!

  • Very helpful as always. Thanks!

  • This is great. But as a few others have mentioned, it just doesnt seem right to be putting UI validation messages into the Data Annotations. Is there a option to put in ResourceIDs there instead or something of that sort.

    Localization too becomes a problem with this model. Have tried looking around through Google for solutions to this problem(I develop for Europe, so localization is a big thing for me, and could be dealbreaker for MVC).

  • Very nice Scott, thanks for the article. We create our model in a separate project, and we do the same for our business logic.. then in the web-app we simply call utility methods in the BLL project to move objects back and forth.

    Will DataAnnotations work on our data-layer objects that are defined in a separate project as I described above?

  • Hi Scott,

    On the Custom Validation, I've tried Phil Haack blog on validation. It's for Beta version since the javascript used is not supported in MVC 2 release.

    In the following javascript code "get_creators" method does not exist in MVC 2 client scripting scripts.

    "var validatorFactories = Sys.Mvc.ValidatorRegistry.get_creators();"

    It would be great if you could advise me on the methods to enable custom validation on client side.

    Thanks,
    Reza

  • Step 4: Creating a Custom [Email] Validation Attribute

    does not work. Even not call constructor of this new class. Why?

    public class EmailAttribute : RegularExpressionAttribute
    {
    public EmailAttribute()
    : base(@"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$")
    {
    }
    }

    public class ReqisterPage
    {
    [Required(ErrorMessage="Username Required")]
    [StringLength(50, ErrorMessage = "Must be under 50 characters")]
    public string username { get; set; }
    [Required(ErrorMessage = "Email Required")]
    [Email(ErrorMessage="Invalid Email")]
    public string email { get; set; }
    public string password { get; set; }
    public string confirmPassword { get; set; }
    public int Timezone { get; set; }
    }

  • The .NET framework really needs a built-in, non-regex email validation routine. This is a hard bit of code, easy to get wrong, and constantly re-written by everybody for every application. It should be in the framework!

  • dude this is orsome, it took me like 4-5hrs to get this to work, but im so glad i stuck in there.

  • Is it possible to get client validation by using ValidationMessage function instead of ValidationMessageFor ?

    for instance:



    public class Response
    {
    [Required(ErrorMessage = "Url is a required field")]
    public string Url { get; set; }
    }

    public ActionResult Test(Response response) {
    ....

    if (!ModelState.IsValid)
    return View();

    ....
    }

    that didn't work: no validation rules in javascript were rendered


    or is it possible to use ValidationMessageFor for some other model, other than the default one for the .aspx page?

  • How should i validate a Date field ?
    [RegularExpression("^([0-9]{1,2})/([0-9]{1,2})/([0-9]{4,4})$", ErrorMessage = "date is invalid")]
    but if i post 20/20/2222 returns "The value '20/20/2222' is not valid for"...
    and how should i translate that return ?
    sorry bad English

  • I hope I'm not doing anything wrong, but I can't seem to figure out how to get the DataAnnotations to validate when I use UpdateModel. I've googled so much it hurts, and all I can find are examples where the model is bound as a parameter, which I don't like in terms of syntax. Is there a way to get it to validate properly?

  • Hi Scott,

    Thanks for the improvements.

    I see two flaws that will keep us away from this approach.
    1. If I understand correctly, to apply validation on classes generated by tools (Linq to SQL, EF) you break the DRY principle as you have to redefine the properties in "buddy" classes (kind of a weird concept). Imagine you have several thousands fields in the database, I see a nightmare (BTW, Is there a compile time checking to match the properties in buddy classes?).
    2. Many times we have to validate an entity in stages. For instance I first validate the Name and Address fields in an application when the data is collected. Then, when the application is posted, I validate everything (Name, Address, SSN ...). How do I do this?

    Thanks,
    Luc

  • To get the EmailAttribute validation working client side I needed to add this to Application_Start():
    DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(EmailAttribute), typeof(RegularExpressionAttributeAdapter));

  • How come I always get "The value '' is invalid." when I use Html.ValidationMessageFor? Correct validation is however shown in the validation summary.

    Can it have something to do with custom model binders?

  • i was going to ask the exact same thing as martin did above. i have a first and last name field, which in my database are not allowed to be null. when i submit the form (without the clientvalidation enabled) the validationsummary indeed gives the correct text, but next to the textbox comes The value '' is invalid.

    validation works, but it seems somewhere the validation message is overwritten with The value '' is invalid.

    do you have any idea how to fix this? great article by the way. very interesting!

  • Hi Scott, we need to gather error messages from database or somewhere else. I searched the web but couldn't find a intact solution. Does anyone implemented such condition? Thanks.

  • Hi, Stefanvds,

    You meant without server validation, didn't you?

    You should use the RequiredAttribute attribute, with the ErrMessage parameter set to a value you like, such as "Last name required". However, you'll still get the message you mentioned and not the message you set in the RequiredAttribute constructor. The reason for this "bug" is that an exception is raised in the DefaultModelBinder because a field is empty. Also, an error is added to the ModelState's Errors collections. The message to the error is what you see next to your control. If you use the RequiredAttribute attribute, a second error is added to the ModelState's Errors collections, but the message set by you can't be displayed since only the first element in the Errors collections is used. In order to get rid of the first element, and thus see your message you can do something like:

    if (ModelState.Values.ElementAt(4).Errors.Count == 2)
    {
    ModelState.Values.ElementAt(4).Errors.RemoveAt(0);
    }

    This code check whether there are two errors in the Errors Collections for the fifth field(e.g. FirstName), and if it does, removes the first error which was added without being asked by the MVC Framework. Now you can see your own assigned message. You can either place this code in the Controller's action, or create a class derived from the DefaultModelBinder, and do that there.

    I wonder whether this is a bug or not. I was looking for a better way of achieving this.

    Hope this helps ;-)

  • Hi Scott - thanks for the post and thanks for ASP.Net MVC!!

    My question is - I've found using validation via DataAnnotations works great if I'm using the DefaultModelBinder; however, I have an instance where I needed to implement a custom model binder and the DataAnnotations validation does not trigger - that is, none of the validation rules (that I have adorned to my model properties) are enforced.

    Is it even possible to do this?

    Thanks in advance Scott!

    -Mark

  • where is "friendToCreate" ??

  • I hava some questions.

  • when i modify the 'person.edmx',the '[MetadataType(typeof(Person_validation))]' is lost.
    How to solve the?

  • I would like to migrate on Blogengine can you explain further why i have to chose blogengine? Thanks

  • This is all very well and good, except when you start getting into real-world business applications. I'm currently working on one, using MVC2/.NET4, and the problem with model validation we've encountered is when something on a form is optional depending on other data on the form. The classic example is a payment form - has a radio button to pay with check or credit card, whichever you choose, it hides the 'other' fields. In the model, both CheckModel and CreditCardModel have required fields, and the properties are decorated with [Required]. With a small tweak to the client validation library, jquery happily doesn't perform validation against a field or fields that are not visible. The problem occurs on Post to the action method - the model binder has no awareness that a field has been hidden, and because it was created on the render side, it thinks it must be required on the POST. The model binder helpfully sets the model state as invalid, and we're stuck. It doesn't seem to follow KISS if I have to create a custom model binder for every form that has a similar design need.

  • Too bad the only way to localize validation error messages is through resx CustomTool's result (Generated Resource class). My validation message are in a database. I could create a T4 to generate such object from the database but I don't want the database content to be involved in the compilation.

    Any suggestion ?

  • This is great. Just what i was looking for and a welcome addition to validation which required custom solutions in asp.net mvc 1. Looks like this will d most of what I need for validation with very little friction. Cool!

  • I have been playing with the client-side validation from this example - if I have a [RegularExpression] validator for the email field, then the client side validation "just works". However, when I implement the [Email] attribute (deriving from the [RegularExpression] attribute) then the client side validation doesn't work. I've done some reading and it seems I have to implement a DataAnnotationsModelValidator and a client side validator function. I can understand the need for this for more "custom" validation, but surely if the custom attribute is derived from one of the "baked in" validators (StringLength, Required or RegularExpression) the client side rules should fire?

Comments have been disabled for this content.