It makes no difference what kind of development you are working on, user input validation is always an important and often troublesome issue.
What data needs to be validated? What are the valid conditions? Do we need to report every error in one pass or allow the user to correct one error at a time? Do we validate on the client or on the server? The questions go on.
Worse than that, the code can quickly get unmanageable, especially where we try to validate everything in one pass. Nested ifs, deconstructing strings, building up lists of error messages, endless comments trying to make some sense of it.
It is my personal opinion that everything that can be updated by anyone else but me should be validated at every opportunity and that we should always validate everything in one pass. But that does not mean that I have never tried to dodge the bullet on a tight deadline.
In some respects, it can be worse for the web page developer. It is important to validate as much as possible at the client to save on bandwidth, but HTTP requests are so easy to fake; the same data needs to be validated again on the server, if you want any kind of security.
Another problem can arise if the customer wants you to mark the invalid fields and then list the errors in one place (a common user-friendly convention in web-page design).
It is hard to imagine someone who enjoys writing validation code, and that goes double for classic ASP developers. Thankfully, the .NET framework has gone a long way to alleviate the problem for the ASP.NET developer with the introduction of six all-encompassing and developer-friendly validation controls:
|Ensure that a mandatory field is populated.|
|Compare one control with another or with a literal.|
|Check that data is within a given range.|
|Use where data must match a given Regex format.|
|Use a custom validation function to validate a control.|
|Collate the results of an entire form's validation.|
This article assumes a basic knowledge of adding controls to a web form and setting the properties and event handlers. It attempts to give a general overview of these controls and how to use them to perform simple practical tasks.
All examples use C# with
GridLayout pages. But anything in this article should easily translate to VB.NET and / or
All of the above, with the single exception of
ValidationSummary, are derived from the
BaseValidator class and share some functionality.
CustomValidator allows you to define your own validation routines, using an event handler on the client, server or both.
The actual client-side validation takes place in events triggered by a change of value in the control you are validating and when you try to submit the form. The server-side validation takes place when you post back the form and the validation results can be accessed using the
Each control's properties look reasonably similar. Apart from the standard font and formatting properties, each of the standard controls has the following common properties, derived from
|Name of the control we are validating.|
|The error message related to an invalid condition.|
|Text to display in this control if invalid.|
|Validate client-side and server-side.|
|The validation result of this control|
string containing the name of the
Control object that the validation control will examine. This control must be developed using the
Of the standard controls, the only ones marked with a
It is worth bearing this in mind if you are ever developing a control that may require validation. You should always prefix the class definition with
MyProperty is the name of the property that can be changed by the user input, usually text).
This defines the message related to the invalid condition. This can be displayed in the control itself or passed to a
The text to be displayed in the control when the condition is not valid. If left blank, the control will display the
If the difference between
.Text is confusing, read on. It should make sense by the time we examine the
ValidationSummary control. Until then, we will only use the
.ErrorMessage property (
.Text should be left blank)
By default this is set to
true and the
.ControlToValidate will be validated twice, at the client and at the server.
.EnableClientScript property is set to
false, then validation will be limited to the server.
The only property not available to the WebForm designer,
.IsValid contains the validation result for this control after the form's validation has taken place.
This can be useful if you want to react differently when only part of the page is invalid.
The following sections will refer to a very simple example. As shown in the screenshot, this example will consist of a single
TextBox being validated. You know the kind of thing: Leave your E-mail address here and we'll send you something really nice for free. (and then sell your email address to five hundred Email spammers)
Create a web form, containing only a
Label ("Email Address:"), an empty
TextBox, a submit
Button and whichever -Validator control we are looking at. (see sample image)
ControlToValidate property should always point to the
TextBox and the
ErrorMessage should contain something relevant to the validation we are working with.
Include some code in a
Button_Click handler to redirect to another page when the button is clicked, but only if the page is valid. For example:
private void myButton_Click(object sender, System.EventArgs e)
Or... if you are feeling lazy, you can download the sample code at the top of the page and unzip it into a new or existing web.
NOTE: There is a strange behavior quirk in the interaction between web browsers and the .NET framework which means that if you hit Enter in a Single-
TextBox form it will post back to the server but the
Button_Click handler is not executed.
This is apparently a legacy browser issue where, for a single textbox form, the button name is not sent as part of the response, leaving .NET with no idea what triggered the postback.
Possible workarounds are:
- Always physically click the Submit button rather than pressing Enter.
- Include a second
TextBox that does nothing, just to avoid this "feature".
- Download and use MetaBuilders' Default Buttons Control to safely link the Submit Button to the
TextBox's enter key.
(Thanks to Andy Smith for helping me understand this)
As the name suggests, the
RequiredFieldValidator is normally used to validate that a mandatory field is populated. It can also be customized so that blank is a valid response and some other text means that nothing has been entered.
There is only one property unique to the
|Consider this text to be "no change" and blank to be "updated".|
Validate our simple form, using a
If you set
false and run the application again, then you will see that the submit button now forces a postback but the field is still validated, so if a malicious user attempts to forge the HTTP request to bypass your validation, it will not be successful.
And there you have it. You have now successfully implemented ASP.NET validation with one control and one line of code (
if (this.IsValid)). How easy can it be?
.InitialValue property gives you an opportunity to enter some text into the
TextBox and still ensure that it is edited before submission.
Try changing both the
TextBox.Text to "EMAIL ADDRESS" and running the application again.
You should find that if you do not change this text and simply hit "Submit", you will get the error message as specified, but now if you blank the field then it is considered valid.
In many ways, this is a functionality overlap with the
CompareValidator, as will become clear later on. But in some cases it is more sensible (i.e.. more readable) to use the
RequiredFieldValidator - for example, validating that a
DropDownList has changed from the "Please Select One..." default.
RangeValidator both compare values to literals or other user-entered data. The two controls inevitably contain some common functionality and thus are derived from the
BaseCompareValidator only offers us one property in addition to those offered by the
|Allows strings of specific formats to be compared accurately.|
This one property, however, is very important and includes several "gotchas" that you might need to be aware of.
.Type property can be used to define how a string is treated. If a textbox is used for numeric, date or currency values, you can use one of the
BaseCompareValidator controls to validate the type of data entered or compare it to a value of the same type more accurately.
e.g.. If compared directly as strings, "90" is greater than "100"; but if compared as numbers, "90" is clearly less than "100".
But be aware that both the Client and the Server validation will deal with the input data using the locale of the Server machine, unless you set the page or application
UICulture properties (see globalization in MSDN).
If you do not set the
Culture and, like me, you develop primarily on an English locale machine (date format: DD/MM/YYYY) and then run your sites live on a US locale server (date format: MM/DD/YYYY) then, as you can see from the screenshot above, the data will be validated differently in development from live.
The 10th of January is before the 1st of October, after all, whichever country you come from.
It is always worth noting on your page which format the user is expected to use (remembering that YYYY/MM/DD is considered culture-independent), but the more idiot-proof you make things, the bigger idiot the internet produces. You cannot guarantee that the user will pay attention to instructions and even if you ask for YYYY/MM/DD, you will still get someone trying to use MM/DD/YYYY without even suspecting that your machine has an English Locale.
It is strongly recommended that you always (even if you develop on the live machine, or one very similar) specify a
Culture in the Web.Config file, for example:
Once you have done this, you know exactly where you stand. You can request the date in format MM/DD/YYYY format and if the user chooses to ignore that and use a culture-independent style then there is no harm done.
If you do not specify a culture, even in the
@Page clause, then you need to be especially careful when comparing to a literal, which may be treated differently in development from production (in fact may cause an exception, if the locale is different and the value becomes invalid). You must then use a culture-independent style for literal dates.
All of this applies equally to numerics in countries which take a comma (,) as a decimal point and to systems using different currency symbols.
Another thing to watch out for is that if any of the values being compared are not of the type the validation is expecting (and in the case of dates, this includes DD-MMM-YYYY, eg. 10-Jan-2003), the form data will be considered valid. The reason for this is that an extra
CompareValidator (using the
DataTypeCheck operator described below) gives you a way out of this and you would generally expect the error message to be different.
CompareValidator is, at first glance, the least useful of the standard validation controls. However it does have its place and has plenty of designer properties (including the
BaseCompareValidator.Type property, see above) to tweak its functionality in interesting ways.
|Compare the value in this control to the value of another control.|
|In what way should we compare the values?|
|Compare the value with a literal value.|
In the simple example, we can use this control to ensure that no one uses a specific E-mail address in the form (I mean, we don't want someone registering us for our own spam E-mail scam, do we?).
CompareValidator in place of the
RequiredFieldValidator; set the
Equal would ever be the default is beyond me!) and the
.ValueToCompare to your own E-mail address. Do not forget, of course, to set the
.ErrorMessage properties, as before.
When you run the application and try to enter your own email address into the form, the validator should give you a message as soon as you leave the
TextBox. It should also refuse to let you submit the form to the server.
As pointed out before, this is not entirely useful in itself; for the rare occasions you would use this, you would not mind hacking the
RequiredFieldValidator to do your bidding.
Only when you start considering the combinations of the unique properties listed above do you realize how powerful this is.
Instead of comparing a control with a literal value, you can compare it to another user-entered string. You do this by pointing the
.ControlToCompare property to the control you wish to validate.
If this and
.ValueToCompare are both set,
.ValueToCompare will be ignored.
It is not only possible to compare values for equality (or inequality), it is possible to look for
In all cases, if the condition is true then the
.ControlToValidate is considered valid.
Alternatively, you can even check that the input data can be converted to a certain type, using the
DataTypeCheck value in this property. This is essential, as pointed out above, because a comparison including an invalid value will always be treated as valid.
For example, when comparing two dates, if "F" is compared to "01/01/2003" then it is simultaneously considered to be greater than, less than and equal to. But when checking "F" using a
.Operator = DataTypeCheck and
.Type = Date, validation will fail.
.Operator = DataTypeCheck, the
.ControlToCompare properties are both ignored and the
.Type property is used to define the valid type.
RangeValidator is much like the
CompareValidator control (hence the common base class), except that it verifies that the user data falls between two constant values, rather than comparing it to a single value (constant or variable).
With that in mind, the control's unique properties (not part of
BaseCompareValidator) are much as you might expect.
|Value may not be greater than this.|
|Value may not be less than this.|
Referring to our simple form, we can easily use a
RangeValidator to verify that the email address entered begins with a lower-case alpha character. Of course, this is not much validation for an email address, but it is a good demonstration of the
Replace whichever validator you are using with a
RangeValidator, set the
.ErrorMessage as for any validator. Then set
Now any string entered that begins with a lower-case alpha character will be considered valid. Note again that if the
TextBox is left blank, it is still considered valid. A separate
RequiredFieldValidator must be used if the field is mandatory.
The value entered by the user may not be greater than this, but the two values can be equal.
The value entered by the user may not be less than this value (unless blank), but the two values can be equal.
Arguably the biggest, most versatile weapon in the ASP.NET validation arsenal has to be the
With just one custom property over those provided by the
BaseValidator class, a world of options become available.
|Value must be in the format described.|
In our simple example, replace the current validator with a
RegularExpressionValidator and set the
.ErrorMessage as usual.
\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*. If you are using Visual Studio .NET, you can click the ellipses (...) button alongside the property and select
Internet Email Address from the default list.
Whilst not perfect email address validation (see below), this is a pretty good approximation. It ensures that the address consists only of "word" characters (A-Z,a-z,0-9,_) with exactly one @ symbol and at least one period (.) after it, allowing for variations which include hyphenations in mid-word and extra periods before and after the @ symbol.
Again, notice that a blank field is always valid unless you also use a
RequiredFieldValidator. And, as with all validation controls, no code is required to perform an identical validation on both the Client and the Server.
The data entered, if not blank, must match the format specified in regular expression format.
This article will not attempt to cover regular expressions in detail, much has been written elsewhere on this site and others on this subject.
Frankly, I do not claim to understand it that well, I usually manage with the default values provided by Visual Studio .NET or others that I find through Google (there are some fascinating expressions out there, if you look hard enough).
The Visual Studio .NET default values can be found via the ellipses (...) button to the right of the property (within the property sheet) and offer the following validations:
US / French / German / Japanese / PRC Phone Number
US / French / German / Japanese / PRC French Postal Code
US / PRC Phone Number
Internet Email Address
There are some surprising omissions here (certain nationalities, US State Abbreviations, ISBN, Credit Cards, Long Date Formats), and some of the default expressions (inc. Email address) are not 100% accurate.
The Regular Expression Library is the best resource I have found for most of those that are missing and for improving those that exist.
If anyone has other resources, I would be happy to list them with the next update.
Sooner or later (probably later, to be honest), you are going to need to validate something and the standard validators are not going to offer it. Maybe you need to access a database, or perform some complex validation involving numerous controls.
If you are going to need to do it repeatedly, you might want to consider creating your own validation control, but for the one-off oddity you can use the
CustomValidator allows you to add code to be run on the client and / or the server and set a value showing the result.
You can populate the
.ControlToValidate property, passing the value of the control to the event handler or script. But, unlike the other validation controls, the
CustomValidator will not throw an exception if
.ControlToValidate is empty.
Other than that, it acts exactly the same as any other validation control, either showing the
.ErrorMessage in the control itself or passing it to a
CustomValidator has only one unique property and a unique event handler.
|Name of HTML-scripted function to execute, on validation|
|Event handler for server-side validation.|
Using our simple example once more, replace the validation control with a
CustomValidator. Set the
.ErrorMessage properties as before. Ignore the
.ClientValidationFunction property for now and add an event handler for the
You can validate the value entered against a database, if you wish. For simplicity, I have chosen to simulate this with a simple
private void alreadyInUse_ServerValidate(object source,
// Default Value
args.IsValid = true;
// Simulating a check against a database
if (args.Value == "firstname.lastname@example.org")
args.IsValid = false;
The validator will always post back to the server to the
ClickEvent handler which the requests the results of the validation. But if you enter one of the "existing" E-mail addresses (in my case, my own address) then the error message will be reported back and the
Response will not be redirected.
ServerValidate event itself, in fact all server-side validation, is executed after the
Page_Load event and before any other events. But the result of the validation is irrelevant unless you later check that the form is valid. The
Button_Click event, in this case, is still executed.
As you can see in the example above, the
ServerValidate event handler should accept an object (the
CustomValidator) and arguments of type
ServerValidateEventArgs class exposes two properties:
.Value. All you have to do in most cases is check that
.Value is valid and set
If there is no
.ControlToValidate property set for the
args.Value will default to
String.Empty, but you can still validate the values contained in the controls.
The sample C# code above would directly translate as:
function alreadyInUse_Validate (source, args)
args.IsValid = true;
if (args.Value == "email@example.com")
args.IsValid = false;
All that is left to be done is set the
.ClientValidationScript property to
alreadyInUse_Validate and the client-side validation is complete.
It should be fairly clear by now that many web pages are going to include a lot of validation controls. No user is going to be happy with all those error messages popping up at random positions around the page, but it is always nice to have something marking the invalid fields.
And this is where the
ValidationSummary control comes into play.
ValidationSummary derives directly from
WebControl and is not related to the other controls except by symbiotic functionality.
When a page is validated, all of the
.ErrorMessage properties from validation controls in the same container (e.g..
DataGrid row) that fail validation are passed to the
ValidationSummary control to be displayed in an unordered list.
This finally explains the
.Text property, common across the validation controls. If
.Text is populated then it will be displayed in place of the validation control, but still
.ErrorMessage will be used to populate the
ValidationSummary control has a number of unique properties that affect the way messages are displayed to the user.
|How the unordered list is rendered.|
|Should the error list be updated during client validation?|
|Defines the text that heads the error list.|
|Render the error messages on the page itself.|
To demonstrate the full power of the
ValidationSummary, it is necessary to come up with something a little more complicated than the simple example that is used throughout the rest of the article.
Consider a simple registration form for, say, a chat room.
The customer requesting this form has asked for the following:
- User ID - mandatory, must be 6-8 characters
- Password - mandatory, must be 8 characters with at least two numeric, also confirmed
- Name - mandatory
- E-mail - mandatory, must be valid format
- Sex - mandatory, drop down list, must not default
- Date of birth - not mandatory but must be valid if entered
Set the form up yourself, complete with validators, using the rest of this article as a guide. As well as giving each control an error message, change the
.Text properties to
* and drop the new (much smaller) control next to the control it is validating.
Although the Visual Studio .NET IDE will not allow you to drop validation controls directly on top of each other, you can edit the HTML view to force the controls into the same position.
Along with the diagram, here is a clue: there are 12 validation controls in total:
- 6 x
- 4 x
- 2 x
ValidationSummary at the bottom of the page, next to a submit button. The only property you might want to set is the
.HeaderText. (In the example, it is set to
Please fix the following errors:)
Run the form and you can now see how a combination of validation controls and a
ValidationSummary control can be used to create a very secure and yet flexible and most importantly usable Web Form.
If you get stuck then, again, the example is included in the downloadable zip file at the top of the article.
The list can be rendered in any of the following
BulletList (list items in an unordered list)
List (delimited only by a new line)
SingleParagraph (delimited by space)
The default option is
true and the list of errors will be shown when the form is submitted.
.EnableClientScript is set to
false then the
ValidationSummary will not be shown until the server reports the errors back to the client machine.
This is useful if (and only if) the
.EnableClientScript property of all the validation controls are also
false. If they are not then the form will not post back to the server and the
ValidationSummary will never report the errors.
Allows the definition of text to describe the list of errors. This will be posted directly before the list of error messages, regardless of the
If set to
alert() call to display all of the error messages in a message box.
The message box will emulate the style defined in
.DisplayMode as closely as possible.
If set to
ShowSummary property renders the list of error messages into the HTML at the position of the
ShowSummary should always be
true, but they should only both be true if absolutely necessary.
If you have two postback events (e.g.. "Next" and "Back" buttons), and one requires validation while the other does not, you can set the
.CausesValidation property of one control to
true and the other to
This will bypass both client and server validation. You can still check
this.IsValid, if you want to use some common code for handling both events, and validation will succeed even if there is no valid data entered.
This is a very powerful set of controls with very few obvious dangers. As an added bonus, they are incredibly easy to implement. In Visual Studio .NET, it is just drag-drop and select a couple of properties.
There is a lot of information to absorb in one pass, but hopefully this article will serve as a reasonably simple reference guide as well as a "How to" guide.
Once you have used the validation controls a few times, you will be dropping them into pages just for fun.
Simply drop the files into any web application, include the .aspx files in the project and set anvindex.aspx as the start page.