Click here to Skip to main content
Click here to Skip to main content

Creating Client and Server-Side Form Validation using the Validator Toolkit for ASP.NET MVC

By , 12 Feb 2008
 

Introduction

Microsoft just released the first preview of ASP.NET MVC Framework and it's Microsoft's way to develop Web applications based on the model-view-controller architecture. It will not replace the classic ASP.NET WebForms model. For more information about the new Framework, please see the Scott Guthrie's blog message.

Since there is just a first preview version available, the final feature list is not complete. At this point of time, there is no built-in solution to validate an HTML form on the client and server-side using a standardized system. The Validator Toolkit for ASP.NET MVC offers a way to do form validation on the client and server-side using validation sets. The toolkit is a new project on Microsoft's Open Source Community site at CodePlex.com.

NOTICE: The latest version of the source code and the sample site for the Validator Toolkit can be downloaded from the CodePlex project (source code tab).

The screenshots below give you an idea about how the toolkit will work:

Screenshot1.jpg

Screenshot2.jpg

Here's another screenshot showing how the error messages can be displayed:

Screenshot3.jpg

Now, let's start!

Solution

As mentioned above, the toolkit uses validation sets as a crucial element. Validation sets are special classes that derive from the ValidationSet base class and define all validation rules (validators) for an HTML form. The toolkit generates client-side JavaScript code based on the defined validators during the view rendering.

The client-side uses the very powerful jQuery JavaScript library in conjunction with the jQuery validation plug-in to fulfil the final task of client validation. For more information regarding jQuery and the plug-in, please take a look at the following links:

The validation plug-in used by the toolkit is slightly customized to support all the needed behaviour. Besides using the jQuery library for client validation, you can use it for a lot of other stuff, like animations or DOM manipulation. There are also a lot of plug-ins developed that extend the core library. Validation sets are also used to validate forms on the server (based on the Request.Form collection).

Before we go ahead, let's have a look at a sample validation set:

public class LoginValidationSet : ValidationSet {

   protected override ValidatorCollection GetValidators() {
   
      return new ValidatorCollection (
         new ValidateElement("username") 
            { Required = true, MinLength = 5, MaxLength = 30 },
         new ValidateElement("password") 
            { Required = true, MinLength = 3, MaxLength = 50 }
      );
   }
} 

This LoginValidationSet class defines the rules for validating a simple login form by overriding the GetValidators method of the base class. The method must return a ValidatorCollection instance with all validators used to validate the HTML form later on. In this case, the username field is required and the input for it must contain at least 5 characters and a maximum of 30 characters. The password field is required too, but within the boundaries of 3 and 50 characters.

The order of the defined validators also defines the execution order of validation process. If the toolkit would use custom attributes to set validation rules instead of the method GetValidators, there is no guarantee for the validation process to validate in the same order the attributes are defined, since the Type.GetCustomAttributes method returns the attribute list in alphabetical order.

Of course, you can also write your own custom validators or you may use the ValidateScriptMethod validator which allows you to call a specific JavaScript function on the client-side and a method within the validation set class for the server-side. More on that later.

Once a validation set class is defined, you attach it to the view and the HTML form processing controller action using the ValidationSet attribute, like this:

//
// File: LoginController.cs
//
public class LoginController : Controller {

   [ControllerAction]
   public void Login() {
      RenderView("Login");
   }

   [ControllerAction]
   [ValidationSet(typeof(LoginValidationSet))]
   public void Authenticate() {
      if(this.ValidateForm())
         RenderView("Overview");
      else
         RenderView("Login");
   }
}   

...

//
// File: Login.aspx.cs (CodeBehind)
//
[ValidationSet(typeof(LoginValidationSet))]
public partial class Login : ViewPage {

   [ValidationSet(typeof(LoginValidationSet))]
   public partial class Login : ViewPage {
   }
}

The controller action Authenticate then calls the ValidateForm method, which uses the ValidationSet attribute to do the server-side form validation, based on the NameValueCollection Request:Form.

Within the HTML page, you need to initialize script validation for the login form (loginForm) as follows:

<script type="text/javascript">
   $(function(){
     updateSettingsForSample1ValidationSet($('#loginForm').validate({rules:{}}));
   });
</script>

In the next step, you define the HTML form as usual:

<form id="loginForm" action="/Login/Authenticate" method="post">
   Username: <input type="text" id="username" name="username" /><br />
   Password: <input type="text" id="password" name="password" /><br />
   <input type="submit" value="Login" />
</form> 

Finally, the script that defines the validation rules must be defined:

<% this.RenderValidationSetScripts(); %>

You also need to include the jQuery JavaScript library into the form or master page. See the Validator Toolkit sample site for more information. Sample site of the toolkit includes the scripts in the master page:

<script type="text/javascript" src="../../Content/jDate.js"></script>
<script type="text/javascript" src="../../Content/jQuery.Core.js"></script>
<script type="text/javascript" src="../../Content/jQuery.Delegate.js"></script>
<script type="text/javascript" src="../../Content/jQuery.Validation.js"></script>

That's basically all you need to do - include form validation on the client and server-side. The next section gives you an overview of the standard validators and their usage.

Standard Validators

The toolkit offers a handful of standard validators out of the box. The following table gives you an overview of the provided validators:

ValidatePresence Validates the presence of input value.

Sample:
new ValidatePresence("username")
ValidateDate Validates input value against the given date formats. Setting the DateFormats property to a comma-separated list of date formats, allows you to check if the value is formatted in one of the specified formats. You may check for date formats like MM/ DD/ YYYY. If DateFormats is not defined, then the validator will use the culture information of the current thread.

Sample:
new ValidateDate("startDate", "yyyy-mm-dd,yyyymmdd")
new ValidateDate("startDate") 
    { DateFormats = "yyyy-mm-dd,yyyymmdd" }
ValidateMin
ValidateMax
ValidateRange
Validates input value either against a minimum, maximum or integer range.

Sample:
new ValidateMin("step", 5)
new ValidateRange("step") { Min = 1, Max = 99 }
ValidateMinLength
ValidateMaxLength
ValidateRangeLength
Validates input value either against a minimum, maximum or integer range.

Sample:
new ValidateMaxLength("password ", 30)
new ValidateRangeLength("password") 
    { MinLength = 5, MaxLength = 30 } 
ValidateElement Joins multiple validators into one validator to keep things simple and allows the following to validate: Required, Min, Max, MinLength, MaxLength

Sample:
new ValidateElement("username") 
    { Required = true, MinLength = 5 } 
ValidateEqualTo Validates input value against another input value. This validator is useful to compare password inputs.

Sample:
new ValidateEqualTo("password", "passwordAgain") 
ValidateScriptMethod Validates input value using a custom JavaScript function and validation set class method.

Sample:
new ValidateScriptMethod("username") 
    { MethodName = "valUsername" }
new ValidateScriptMethod("username") {
MethodName = "valiUsername", 
    Parameters = "{Opt1:2, Opt2: "AB"}" } 

There are still some validators missing, e.g. a general regular expression validator or a specific email validator.

Validation Sets

Each validation set definition class derives from the ValidationSet base class. This base class contains and offers common functionality for the validation process. Let's take a look at the sample below to explain some possibilities the validation set offers to validate complex forms:

public class LoginValidationSet : ValidationSet {

   string Username = "";
   string Password = "";

   protected override ValidatorCollection GetValidators() {
      return new ValidatorCollection
      (
         new ValidateElement("username") 
            { Required = true, MinLength = 5, MaxLength = 30 },
         new ValidateElement("password") 
            { Required = true, MinLength = 3, MaxLength = 50 },
         new ValidateScriptMethod("username", "validateUsername")
      );
   }

   protected bool ValidateUsername() {
      // DO HERE SOME VALIDATION AND RETURN RESULT AS BOOLEAN VALUE
      return true;
   }

   protected override void OnValidate() {
      if(Username.StartsWith("billy") && Password.StartsWith("gat"))
         throw new ValidatorException("username", "The username/password combination ");
   }
}

Creating non-public instance member fields of type String like the Username or Password fields, allows the base class to populate those fields with the accompanying input field values. This is a simple way to access input values without checking the underlying values collection (e.g. Request.Form).

The ValidateScriptMethod validator defines a JavaScript function (validateUsername) to call during the client-side validation. This function must be defined or included in the HTML page. The ValidationSet base class checks during the server-side validation if the current validation set class contains a case-insensitive method named validateUsername.

Once all validators defined with the GetValidators method are called during the validation process, the base class will call an overall method called OnValidate. By overriding this method you can do some final validation. If you want to throw an exception you need to throw the ValidatorException with the field name and message as parameters.

Using the described techniques, the possibilities of the jQuery library and the custom validators (see below), you can validate most complex forms quite efficiently. The next section will describe ways to localize the messages.

Localization

It's easy to localize error messages of the toolkit using the standard folder. If the default settings are not changed, the default error message for each validator is stored in the ValidationSet.resx file (in the folder App_GlobalResources). The naming convention for the resource key is as follows: <VALIDATORNAME>_DefaultErrorMessage.

To change the default name of the ValidationSet.resx resource file, a derived validation set class can set the name by using the static field DefaultMessageResourceName or by adding the MessageResourceName attribute to the class. It is also possible to combine the techniques and use more than one resource file.

The sample site within the Validator Toolkit contains usage examples of localized error messages and field names. The localization is simple and straightforward.

Custom Validators

Creating custom validators is quite simple, but requires some basic knowledge of the jQuery JavaScript library and the validation plug-in if the validator wants to support client validation. The sample site includes a custom validator called ValidateBuga, which checks the input value against the constant string buga. Each validator derives from the Validator class, which provides a couple of virtual methods a custom validator must override:

GetClientMethodData This method defines by returning an instance of the ValidatorMethodData class the name of the custom validator (for the jQuery validation plug-in), the JavaScript function code and the default error message.
GetClientRule This method returns the plug-in client rule to use once the validator is defined within a validation set class.
GetClientMessage This method returns the localized error message for a given element.
GetDefaultErrorMessageFormat This method returns the default error message of the custom validator.
Validate This method validates the input value for the given element. If the input is not valid the validator must call the InsertError method of the Validator base class to signal an error.

Here is the source code of the ValidateBuga sample validator:

public class ValidateBuga : Validator {

   public ValidateBuga(string elementsToValidate)
      : base(elementsToValidate) {
   }

   public override ValidatorMethodData GetClientMethodData() {
      return new ValidatorMethodData(
         "buga",
         "function(value,element,parameters){return value=='buga';}",
         "$.format('" + ErrorMessageFormat + "')"
      );
   }

   public override string GetClientRule(string element) {
      return "buga:true";
   }

   public override string GetClientMessage(string element) {
      return string.Format("buga:'{0}'", GetLocalizedErrorMessage(element))
         .Replace("'", "\'");
   }

   protected override void Validate(string element) {
      if(Values.ContainsKey(element) == false || (Values[element] ??
         string.Empty).Trim() != "buga")
         InsertError(element);
   }

   protected override string GetDefaultErrorMessageFormat() {
      return "The field {0} must contain the value \"buga\"";
   }
} 

Another way to use custom validation is by using the validator ValidateScriptMethod. It allows to call a JavaScript function on the client-side and a specific method of the validation set class on the server-side. The custom validation is part of the validation set class and is not usable in multiple validation sets.

Summary

The Validator Toolkit is a simple and easy way to add client-side and server-side HTML form validation to the new ASP.NET MVC Framework. It is easy to extend the toolkit by adding custom validators. You may use the toolkit until Microsoft provides a solution for HTML form validation.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

About the Author

Jürgen Bäurle
Germany Germany
Member
I’m a software developer based in Germany, Stuttgart.
 
Homepage

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generaluse validator for a Ajax formmembertuanpm15 May '10 - 16:29 
Hi
I have tried your toolkit, it is great
But I have a small trouble:
- I have a button on page, click event call
$("#idDetail").load("/nwApp/OpenNewDetail/" + idThutuc + "?post=onegate.idDetail&slot=idDetail", function(html) { $("#idDetail")[0].value = html; ValidatorCall(); });
 
this code return a form into div "idDetail"
 
and ValidatorCall jquery:
function ValidatorCall() {
                       
            updateSettingsForSample1ValidationSet($('#formDetail').validate({
                errorContainer: $('#formDetailSummary'),
                errorLabelContainer: $('#formDetailSummary ul'),
                wrapper: 'li',
                rules: {}
            }));
           
        }
But on form, validation did not appear.
But if i put form on the page then validation is ok!
 
May you show me more to my trouble, thanks
GeneralValidation with sys.net.webrequest [modified]memberNaveedAkram6 Feb '09 - 5:39 
i have problem with validation.i am working on ASP.net mvc
page have four validation set,validation script render first time on page load with four validation functions.
these four function within four different js file
 
$(function(){
updateSettingsForForm1ValidationSet($('#Form1').validate({rules:{}}));
});
 
validation is working first time for that "form" which load first time with page.when we call the sys.net.webrequest for update the page(for get the next form) and also call the function from js which is related with that form in call back. but validation is not working and form directly post:
==>no error in error Console at any time
==>js file include top of page
==>js file function have many other function which is working when the function call
==>render script is below then that area which is change with sys.net.webrequest
PlZ send me response
 
modified on Saturday, February 7, 2009 2:17 AM

Generalspecific email and/or regular expression validatormemberMats Jakobsson21 Jan '09 - 22:10 
Hi,
 
Thank you for a great article, the validation system works great!
 
I have a couple of questions though:
1. Are you planning on creating a specific email and/or regular expression validator? And if, when? (really looking forward to it. Smile | :) )
2. I would like to feed my ValidationSet with a validatorcollection from a service layer, is this possible - and if so, how? In your examples you create the validatorcollection in the overriden GetValidators(), I would like to say something like:
 
public class FormValidationSet : ValidationSet
{
public IInputRowsService _service;

public FormValidationSet(IInputRowsService service)
{
_service = service;
}
 
protected override ValidatorCollection GetValidators()
{
return _service.GetValidators();
}
 
}
Does this make sense? Is it possible? Is it even relevant?
 
Thanks again!
 
BR
Mats J
QuestionA couple of little questions...memberScott McKenzie13 Jul '08 - 14:21 
I haven't looked in detail yet, but I do plan on it over this next week...
 
Is it happy with multiple forms on a single page?
Any recommendations on placing the code in OnActionExecuting (can't recall the exact controller event name)?
 
Good work
Thanks
Scott
 
Scott
QuestionCode sample?memberolivier_ntk10 Jul '08 - 20:31 
Hi, nice job.
 
You mentioned that there are some code samples .. what is the link? danke schon!
AnswerRe: Code sample?memberJuergen Baeurle10 Jul '08 - 21:24 
You can find sample code here: http://www.codeplex.com/MvcValidatorToolkit
GeneralAttaching validation rules to elements where the ID is unknown at design-timememberChristoff91526 Jun '08 - 7:21 
We're working with ASP.NET MVC and the jQuery validation plug-in, and I had a question about getting validation to work through ValidationSets on elements where the ID is not known at design-time.
 
Basically, there is a series of dynamically generated dropdowns put onto a page. The ID's for these dropdowns come from a database, and they can number anywhere from 1 to 100 in number. The dropdown values themselves are not used in the form processing after submission (their selected value is combined with the value of a paired up field and the result is stored in a hidden field on the page), so the name attribute is free to use as a selector, but I don't know if this would work the same way in back-end c# code as it does with standard jQuery selectors (ie more css-like).
 
Does anyone have any experience in assigning rules to elements on the page in this type of situation? Any help would be appreciated.
 
Thanks,
Christoff
GeneralToolkit works now with ASP.NET MVC Preview Release 3memberJuergen Baeurle19 Jun '08 - 23:03 
Have a nice day!
QuestionjQuery versionmemberPaulLinton14 Jun '08 - 1:51 
I know next to nothing about jQuery but this doesn't seem to work with V1.2.4 only 1.2.2
Does anyone know how to make it work with that version or V1.2.6 which seems to be the latest?
Any help appreciated.
Paul
PS I know I have probably missed something fundamental as surely a change from 1.2.2 to 1.2.4 wouldn't break existing code!
AnswerRe: jQuery versionmemberPaulLinton15 Jun '08 - 13:13 
I found my own answer. All I had to do was replace jQuery.Core.js with jQuery-1.2.6.js (or, I guess, rename the 1.2.6 version to jQuery.Code.js) and put the Date, Delegate and Validation scripts in my content folder.
GeneralFix for typed viewdatamember leppie 16 May '08 - 1:05 
In ViewPageExtensions.cs:
var errmsgs = vsa.ValidationSet.GetType().Name + ".ErrorMessages";
NameValueCollection errorMessages = viewPage.ViewData.ContainsDataItem(errmsgs) ?	
  viewPage.ViewData[errmsgs] as NameValueCollection : null;
sb.Append(vsa.ValidationSet.CreateClientScript(errorMessages));

 
xacc.ide - now with TabsToSpaces support
IronScheme - 1.0 alpha 3 out now

QuestionHow to use space in the error messagesmemberTony Mortana2 May '08 - 5:48 
He great code!
 
I finaly got it to work. Good code and easy to use when it works!
 
I am using _ within element names now but i want them to be converted
to blank places. Like: 'profile_name' must look like 'profile name' within the error messages.
 
I have looked a litle in the JS code, but i cant findout where to add the replace("_", " ");
 
Any tip ?
 
But realy great code Wink | ;)
GeneralTyped ViewDatamemberMember 405884825 Apr '08 - 13:15 
How does this work with typed viewdata, especially, viewdata types that do not contain
a table of names and values (where the validator can store its error messages).
Any way to work around this?
 
And what happens if I render another object than the viewdata being verified?, for example (in controller)
if (this.ValidateForm())
   RenderView("SomeView", new SomeObject1());
else
   RenderView("SomeView", new SomeObject2())
 
Won't the error messages stored in the ViewData at that point be lost when SomeView is rendered with another object?
I have seen examples floating around using the TempData for validation messages (so the ViewData could be changed),
would that be possible to do?
 
Thanks
/ Anders
QuestionWhat I would like to see...memberSuperShade24 Apr '08 - 9:35 
I would love to see a way to customize the way validators indicate errors. I have a grid control that allows the user to edit every row. Two columns have MaskedEdit controls from the AjaxControlToolkit which highlight the field in red when there is an error. I would like to have validators for the other columns that would display the same way since error messages would ruin the display and I really don't like the ValidationSummary control.
QuestionWhat if I don't want to use jQuery?membertommy skaue23 Apr '08 - 3:05 
Is this example pretty much dependent on jQuery, or is it simple to exchange jQuery with some other js library (ie. prototype)?
 
------------------------------------------
Hey! Stop reading my signature... stop it!
hmm... you're still reading it...

AnswerRe: What if I don't want to use jQuery?memberJuergen Baeurle23 Apr '08 - 4:11 
The validator toolkit depends on jQuery and is the base building block for client validation. If you want to use the prototype lib you have to adpot the server-side code as well.
 
Best regards,
 
Juergen
GeneralError on id's containing "."memberarmasanea5 Apr '08 - 4:37 
Hi,
First of all a great thank you for this tool.
 
I have noticed a small misbehavior and wanted to ask if it has already been reported. If the id of the html element contains a '.'(dot), the generated javascript malfunctions. For example, I has a field named "Algorithm.AlgorithmName", and the client code crashed on this line:
 

function updateSettingsForAlgorithmEditValidator(v){
if(typeof(v)!='object')
return null;
if(v.settings.rules.Algorithm.AlgorithmName==undefined){
v.settings.rules.Algorithm.AlgorithmName={
required:true,
rangeLength:[1,100]
};
}
return v;
}

 
The problem is obvious - rules.Algorithm.AlgorithmName is trying to access the field AlgorithmName on element Algorithm, which is non-existent, of course.
So I went back to validator project and recompiled with slight modifications to replace direct field addressing by indexing into the property collection. The javascript is now:
 

function updateSettingsForAlgorithmEditValidator(v){
if(typeof(v)!='object')
return null;
if(v.settings.rules["Algorithm.AlgorithmName"]==undefined){
v.settings.rules["Algorithm.AlgorithmName"]={
required:true,
rangeLength:[1,100]
};
}
return v;
}

 
The changes were done in ValidationSet.CreateClientScript, and sb.AppendFormat("\tif(v.settings.rules.{0}==undefined)
was changed to
sb.AppendFormat("\tif(v.settings.rules[\"{0}\"]==undefined)
 

Would you be interested to include this in the next release?
 
Thanks!
GeneralError -questionmemberStevieGen29 Mar '08 - 12:09 
I'm using the code for preview 2 and your library from Friday, March 28th
 
When I have a ViewPage with an object attached to the viewdata, ie.
 
[ValidationSet(typeof(EmployeeValidator))]
public partial class EditEmployee : ViewPage
 
I get this error:
 
DataBinding: 'Employee' does not contain a property with the name 'EmployeeValidator'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
 
Exception Details: System.Web.HttpException: DataBinding: 'Employee' does not contain a property with the name 'EmployeeValidator'.
 
Source Error:
 

Line 21: <%--<%} %>--%>
Line 22:
Line 23: <% this.RenderValidationSetScripts(); %>
Line 24:
 
I don't understand this error.
 
Your examples don't show using something with viewdata, can you test this part?
 
Thanks

GeneralRe: Error -questionmemberStevieGen29 Mar '08 - 12:10 
It removed something in my post:
 
I'll try with spaces:
 
public partial class EditEmployee : ViewPage Employee
AnswerRe: Error -questionmemberbszafko1 Apr '08 - 6:38 
I think my blog post solves your problem:
http://bartekszafko.pl/index.php/blog/2008/04/01/mvcvalidatortoolkit_wiht_strongly_typed_[^]
 
I also added a new sample in the source code to illustrate.
 
Have fun! Smile | :)
GeneralRe: Error -questionmemberStevieGen1 Apr '08 - 12:42 
Excellent - thank you!
QuestionValidation with External File?memberSteveC-A914 Mar '08 - 5:01 
Can the toolset be harnessed to somehow use an external configuration file? When rules are only included in code, the rules must be tested with it. In fact, a rule test and a code functionality test are two different things. The Drools project does a very good job with this, and I was wondering if this kit can do the same kind of thing.
 
Thanks.
GeneralGood jobmemberMaxGuernsey18 Feb '08 - 11:39 
It looks like you are using this the way it was intended to be used. I'm not sure I like the architecture itself (the MVP architecture, not what you've done). The point of MVP (which is really Mediator), as with all patterns, is to control coupling yet Microsoft's MVP "architecture" seems to increase coupling.
 
Max Guernsey, III
Managing Member, Hexagon Software LLC
http://www.hexsw.com
http://www.dataconstructor.com

GeneralRe: Good jobmemberJuergen Baeurle18 Feb '08 - 12:28 
Thank you.
QuestionValidate objects directly?memberh52017 Feb '08 - 7:40 
Great work!
And is it possible to do something like this:
 

public class Person{public int Age{ get; set;}}
 
var p = new Person(){ Age=23 };
var ctx = new ValidationContext();
var v1 = new ValidateMax("Age", 200, "Your age is too big.");
ctx.add(v1);
if( !ctx.Validate(p) ) ShowError(ctx.Errors[0]);
 

AnswerRe: Validate objects directly?memberJuergen Baeurle17 Feb '08 - 8:37 
Thank you.
 
You cannot use the the code like this. The toolkit is developed using the infrastructure of the MVC.
 
Juergen
GeneralWell donemvpDaniel Vaughan13 Feb '08 - 21:45 
Very nice article Jürgen. Thanks.
5 x Smile | :)
 
Daniel Vaughan



Blog: DanielVaughan.Orpius.com



GeneralRe: Well donememberJuergen Baeurle13 Feb '08 - 22:56 
Thank you very much.
Generalamembershashib2613 Feb '08 - 20:41 
a
GeneralRe: amemberJuergen Baeurle13 Feb '08 - 22:55 
Thank you.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 12 Feb 2008
Article Copyright 2008 by Jürgen Bäurle
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid