asp:feature
Languages: VB
Technologies: Validation | Validator Controls | Custom Controls
Master ASP.NET Validator Controls
Tightly Control Data Input with Little or No Programming
By Steven A. Smith
The ASP.NET validator controls make it incredibly easy to add validation logic to forms, which eliminates the need for ASP.NET developers to become experts in client-side JavaScript for most validation tasks. What's more, the ASP.NET validator controls perform their validation on both the client and server (or only on the server, if you wish). That's important because malicious users easily can bypass pure client-side validation. In this article, I'll briefly cover the basics of the validator controls, and then I'll describe some advanced validation techniques. See the end of the article for details about downloading the files used in this article.
All of the validator controls (with the exception of the ValidationSummary control) derive from the Label Web control, in the System.Web.UI.WebControls namespace of the .NET Framework. FIGURE 1 displays the class hierarchy of the validator controls. The validator controls inherit from the BaseValidator control. The BaseValidator class cannot be instantiated, but it does define several properties and one method that are common to all of the validator controls.
FIGURE 1: Here's the validator controls'
class hierarchy. Note how ASP.NET takes advantage of the object-oriented
features of the .NET Framework to build powerful controls like the CustomValidator
out of simple controls such as the Label, both of which have their roots
in the WebControl class.
Property |
Description |
ControlToValidate |
The ID of the data entry control that this validator validates. |
EnableClientScript |
Set to False to perform server-side validation only. The default is True. |
ErrorMessage |
The message to display when validation fails. |
IsValid |
True if the ControlToValidate control passes the validation rules. |
Text |
Displayed when validation fails (instead of ErrorMessage). Often used to display an icon next to a control in conjunction with a ValidationSummary control that displays the ErrorMessage. |
Display |
Dynamic | None | Static - controls how the validator control is rendered on the HTML page. |
Method |
Description |
Validate |
Causes the control to perform its validation checks and is called automatically when a form is submitted. |
FIGURE 2: The BaseValidator class defines these properties and methods.
You should know a few things about the properties and methods the BaseValidator class defines. First, the ControlToValidate property must be set to the ID of a control on the page, or the ASP.NET page will fail to load. Second, by default, the Text property will be displayed wherever the validator control is located on the page any time IsValid evaluates to False. If the Text property isn't set, the error message will be displayed instead. Many developers use an asterisk for the Text property to mark invalid fields, and then elaborate with a more detailed description of the problem in the ErrorMessage field. Third, ValidatorDisplay can be set to Dynamic, None, or Static. None will make the validator control invisible. When set to Static, ASP.NET reserves space that the error message will occupy even when the validator isn't visible. When set to Dynamic, space isn't reserved when the validator isn't visible. Finally, you can use the Validate method to make a validator control perform its validation checks. The validator controls normally do these checks automatically, though, so you should rarely need this method.
The BaseValidator control provides a good solid foundation upon which to build. However, you can't actually instantiate and use a BaseValidator by itself. You need to work its child controls, which include the RequiredFieldValidator, CompareValidator, RangeValidator, RegularExpressionValidator, and CustomValidator, in order of complexity. Finally, the ValidationSummary control, which doesn't inherit from BaseValidator, provides a great way to summarize the results of all the validators on a page in one place. See the sidebar "In Short" for a summary of the validators I'll be exploring in the next section.
Common Validators
RequiredFieldValidator. The simplest validator is the RequiredFieldValidator. It only adds one string property, InitialValue, to those of the BaseValidator. RequiredFieldValidator compares the value of a control with its InitialValue property (which defaults to an empty string). If the two are the same, RequiredFieldValidator determines that the value of the control is invalid. The InitialValue property is useful for situations in which the default isn't blank, such as a drop-down list that has as its first value Select an Item. Note, however, that if the InitialValue property is set to something other than an empty string, a blank entry will be considered valid because it differs from InitialValue, which isn't blank. The simplest way to handle both situations is to use two RequiredFieldValidator controls.
Here's an example of using a RequiredFieldValidator to require an entry in the Name text-box control:
Name:
ErrorMessage="Name
is required." ControlToValidate="Name" /> CompareValidator. You use the CompareValidator to compare a control either to a static value or
to the value of another control. The CompareValidator exposes four
properties to define how the comparison is performed. The Type property, a variable of
type ValidationDataType, is used to
describe the type of data expected in the ControlToValidate.
The Operator property, of type ValidationCompareOperator, determines
what kind of comparison the control should perform and includes options such as
LessThan, Equal, and NotEqual. One
important option for the Operator
property is DataTypeCheck. If set, the CompareValidator
control will use this option simply to check that the ControlToValidate property is of the type defined by the Type property. The last
two properties exposed by the CompareValidator
control are two strings: ControlToCompare,
the ID of the comparison control; and ValueToCompare,
the static value against which you're comparing. Only one of these can be set
for a given instance of a CompareValidator
control. The
following code illustrates how to use the CompareValidator
to validate two dates, one of which must follow the other. The first CompareValidator, StartIsDate, uses the DataTypeCheck
operator to verify that the StartDate
is of type Date. For this kind of
validation, neither ControlToCompare
nor ValueToCompare need be set. The
second validator, DateCompare,
checks to make sure that EndDate is
greater than or equal to the StartDate: Start Date: End Date: ControlToValidate="StartDate"
Type="Date" Operator="DataTypeCheck" ErrorMessage="StartDate
must be a valid date." /> ControlToValidate="EndDate"
ControlToCompare="StartDate" ErrorMessage="End
Date must be greater than Start Date." Operator="GreaterThanEqual"
Type="Date" /> RangeValidator. The RangeValidator control is similar to the CompareValidator,
but is simpler. RangeValidator is only used to verify that a control's
value falls within a specified range, which you specify with the MaximumValue and MinimumValue properties. It also includes a Type property, just like the CompareValidator.
By specifying values for MaximumValue, MinimumValue,
or both, it's very easy to validate that a value falls within an allowable
range. Note that values are always inclusive. The code here demonstrates a
simple use of the RangeValidator: Age:
ControlToValidate="Age" ErrorMessage="Age
must be between 18 and 80." MaximumValue="80"
MinimumValue="18" Type="Integer" /> RegularExpressionValidator. Regular expressions are a powerful
way of describing a wide variety of string patterns. The RegularExpressionValidator is more complex than the other
validators because it requires knowledge of regular expressions, which, to the
uninitiated, tend to resemble a series of random keystrokes. Entire books have
been devoted to regular expressions and their use, and a large number of common
ones are available online at http://RegExLib.com/. This site is a good place to look for common
validation expressions, as well. (I manage the site as part of ASPSmith.com.)
In this article, I'll describe only a few simple expressions. The RegularExpressionValidator control
exposes one string property, ValidationExpression,
and uses it to validate the ControlToValidate
control. The expression must be a valid regular expression, or the control will
throw an exception. Regular expressions use a number of symbols to represent
different kinds of string patterns. For example, the ^ symbol represents the
beginning of the string to be matched, and the $ symbol represents the end of
the string to be matched. For most validation expressions, you'll want the
regular expression to begin with ^ and end with $ because you want to validate
the entire contents of the ControlToValidate
(as opposed to just checking for the existence of a substring within the ControlToValidate control's value). An
important character in the regular expression language is the backslash, or \.
This symbol is used to prefix other characters to change their meaning. For
example, the letter d by itself in an expression normally means the letter d.
However, if you prefix it with a backslash, as in \d, then it means "match any
numeric digit." Following any expression with a number inside curly braces
(e.g., {5}), means that pattern must be repeated a designated number of times.
So, to match exactly five numeric digits, such as for a U.S. ZIP code, the
following expression could be used: ^\d{5}$. If more
than one pattern is valid, you can use the | character between expressions.
This has the effect of saying "match this or match that." Building on
the previous example, a regular expression that would match a five-digit ZIP
code or a nine-digit ZIP+4 code (with hyphen), would be: ^\d{5}$|^\d{5}-\d{4}$. Using this expression, the
following code demonstrates how to validate a text box that contains a valid
ZIP or ZIP+4 code: ZIP Code:
runat="server" ErrorMessage="ZIP
Code format must be 55555 or 55555-5555." ControlToValidate="ZIP"
ValidationExpression="^\d{5}$|^\d{5}-\d{4}$"
/> CustomValidator. When the other validators just
can't get the job done, that's when it's time to use the CustomValidator. As its name suggests, this control allows you to
define the validation logic yourself, to allow such things as credit-card
verification or e-mail Mail Exchanger record look-ups to be performed as part
of the validation. The CustomValidator
exposes one property, ClientValidationFunction,
which you use to designate a client-side function for validation. The CustomValidator also supplies the ServerValidate event, which you use to
tie in the server-side validation for the control. When you specify a function
name for OnServerValidate, the CustomValidator will use that function
to perform its validation on the server. Both the
client-side and server-side functions must follow a specific format in order to
work with the CustomValidator. The
server-side function must be a sub (void in C#) and must take two parameters,
an Object argument and a System.Web.UI.WebControls.ServerValidateEventArgs
argument. The listing in FIGURE 3 shows an example server-side validation
function to check if a form contains a perfect square (a number whose square
root is an integer): Protected Sub validateSquare(sender As Object, _ e As
System.Web.UI.WebControls.ServerValidateEventArgs) Dim _sqrt As Integer Try 'Get the square root rounded to nearest
integer _sqrt = Int32.Parse(Math.Round(Math.Sqrt(
_ [Double].Parse(e.Value))).ToString()) 'Compare the rounded square root,
squared, with 'the original value and return true if
they are equal. e.IsValid = (Int32.Parse(e.Value) =
_sqrt * _sqrt) Catch 'Return false if any exceptions occur e.IsValid = False End Try End Sub 'validateSquare FIGURE
3: The server-side
validation function for a CustomValidator, the validateSquare method, must
take two properties, an object and a ServerValidateEventArgs.
The value to be validated is provided in the ServerValidateEventArgs' Value property. After validation, you must set the ServerValidateEventArgs' IsValid property appropriately. This
routine, validateSquare, takes the
value to be validated (e.Value) and
computes the square root of the number, rounded to the nearest integer. Then,
the routine sets the e.IsValid
property to the result of the comparison of the original value with the square
of the rounded square root. For a perfect square, where the square root is an
integer, the two values will be equal, and IsValid
will be set to True. Otherwise, IsValid is set to False. As an additional measure, if there are any errors converting
the value from a string to an integer, the Catch
block sets IsValid to False. Although
this is a very simple example, you can see how you could add as much complex
business logic to this validation function as you need, making CustomValidator a powerful tool.
Unfortunately, this function is only called when the form posts back, meaning
that it requires a round trip to the Web server for each validation. In order
to support client-side validation, the ClientValidationFunction
property must be set, and that function must be registered on the page. The
following code demonstrates how to add a client script block to an ASP.NET page
programmatically: Private Sub
Page_Load(sender As Object, e As System.EventArgs) Dim validateScript As
String = _ "" Page.RegisterClientScriptBlock("validateSquare",
validateScript) End Sub
'Page_Load Here's
the HTML generated by ASP.NET to support the client-side validation: The
following HTML wires up these client- and server-side validation functions.
Note the use of both OnServerValidate
and ClientValidationFunction: Enter a Perfect
Square (the square of an integer) Display="Dynamic"
OnServerValidate="validateSquare" ControlToValidate="square"
ErrorMessage="Value
must be a perfect square." ClientValidationFunction="isPerfectSquare"/> ValidationSummary. By default, error information is
displayed at the location of the validator control. However, displaying verbose
error messages like this can play havoc with the layout of the form, and it is
often more user-friendly simply to summarize the validation errors found and
mark invalid entries somehow. The ValidationSummary
control serves as a way to organize all of the validation error messages in one
place, usually at the top of the form, so that, at a glance, a user can tell
which fields need to be corrected. The ValidationSummary control can be
rendered in a variety of formats, as specified by the DisplayMode property. These include a simple list, a bulleted list
(the default), or a single paragraph format. Optionally, the summary can be
hidden by setting the ShowSummary
property to False, and the summary can be displayed in a pop-up message
box if the ShowMessageBox property
is set to True. Finally, you can use the HeaderText property to add a standard header to the list of
validation errors. The listing in FIGURE 4 shows a simple form with three RequiredFieldValidators and a ValidationSummary control. FIGURE 5
shows the output after submitting the form with no completed fields. Name:
ErrorMessage="Name
is required." ControlToValidate="Name">* Rank:
ErrorMessage="Rank
is required." ControlToValidate="Rank">WRONG! Serial Number:
runat="server" ErrorMessage="Serial
Number is required."
ControlToValidate="Serial"> FIGURE
4: With the addition of a ValidationSummary control to this Web form, the form will
display all of the error messages for all of the validator controls at the top
of the page so the user easily can see which fields need to be corrected. Note
that the text property of each validator control also will appear in place of
the validator control if it is invalid (e.g., "*" or "Wrong!"). Advanced Validation Techniques Although
the validator controls are a huge step forward compared with what was available
in ASP classic, they still require writing a fair bit of code to perform
anything but the simplest validation. Validation logic can be combined with
other form elements by creating a composite custom control. A custom control is
simply a class that inherits from the System.Web.UI.Control
class and that has two or more child controls. In this case, the ValidZip control has three child
controls: a TextBox, a RequiredFieldValidator,
and a RegularExpressionValidator. By
programmatically instantiating these controls and then adding them to the Controls
collection of your composite control, you can effectively package several Web
controls together into one. Then, this composite control can be placed in the
toolbox in Visual Studio .NET and can be dragged and dropped onto the design
surface of a Web form wherever it is needed. FIGURE 6 shows the code required
to create a composite control for encapsulating the validation logic and input
control for a U.S. ZIP code. Imports System.Web.UI.WebControls Imports
System.Web Imports
System.Web.UI Public Class ValidZip Inherits System.Web.UI.Control Implements INamingContainer Protected myTextBox As TextBox Protected myRequiredValidator As
RequiredFieldValidator Protected myRegExValidator As
RegularExpressionValidator Protected Overrides Sub
CreateChildControls() ' Instantiate Controls ' Create the
TextBox myTextBox = New TextBox() myTextBox.EnableViewState = True myTextBox.ID = "myTextBox" ' Create the
required field validator myRequiredValidator = New
RequiredFieldValidator() myRequiredValidator.ID =
"myRequiredValidator" + _ Me.UniqueID myRequiredValidator.ControlToValidate = _ myTextBox.UniqueID myRequiredValidator.Display = _ ValidatorDisplay.Dynamic myRequiredValidator.EnableViewState =
False myRequiredValidator.Text =
"*" myRequiredValidator.ErrorMessage = _ "ZIP Code is required." ' Create the regular expression
validator(s) myRegExValidator = New
RegularExpressionValidator() myRegExValidator.ID =
"myRegExValidator" + _ Me.UniqueID myRegExValidator.ControlToValidate = _ myTextBox.UniqueID myRegExValidator.Display =
ValidatorDisplay.Dynamic myRegExValidator.EnableViewState =
False myRegExValidator.Text = "*" myRegExValidator.ErrorMessage = _ "ZIP code invalid. Must either be 5 digits " & _ "or 5 digits, a hyphen, and 4
digits." myRegExValidator.ValidationExpression
= _ "^\d{5}$|^\d{5}-\d{4}$" Me.Controls.Clear() Me.Controls.Add(myTextBox) Me.Controls.Add(myRequiredValidator) Me.Controls.Add(myRegExValidator) End Sub End Class FIGURE
6: The ValidZip
composite control combines three other Web controls (a TextBox, a RequiredFieldValidator,
and a RegularExpressionValidator) into a single control that can be
managed more easily and can be reused across many Web forms. To use
this control, you must add a reference to the top of the aspx page, and then
reference the control just like any other Web control, using a prefix and the name
of the control. FIGURE 7 shows a complete ASP.NET page using this control. <%@ Page
language="c#" %> <%@ Register
TagPrefix="cc1" Namespace="CompositeValidationControls" Assembly="ValidZip" %>
"-//W3C//DTD HTML 4.0 Transitional//EN"
>
FIGURE 5: After trying to submit the Web form without filling in the required
fields, the user is presented with a list of invalid-field error messages in a ValidationSummary control at the top of the form, and each
form element has a marker next to it noting that it is invalid.
ZIP:
FIGURE 7: Using ValidZip in an ASP.NET page is as simple as adding the control to the page and ensuring the control is registered, using the <%@ Register %> page directive. Note that the ValidZip control includes both the input (TextBox) and the validation logic, greatly reducing the number of controls needed to build this form.
You can expand upon this technique and apply it to many different common form elements, such as e-mail addresses, phone numbers, and credit-card numbers.
Finally, one last technique to be aware of is the use of the Page.IsValid property, which is set on any ASP.NET page that uses validator controls. After a post-back, this property will be set to True only if the page passed all of its validation tests. Thus, before performing business logic that depends on valid data, you should test this property to verify the page's data has passed all validation tests. You can do this quite simply, with an If Page.IsValid Then statement.
Limitations
One limitation of the validator controls that ship with ASP.NET is that they are completely tied to the user-interface layer of an application. This is because they inherit from the System.Web.UI.WebControls.Label class, a class that's only useful within the scope of the user-interface layer. I've been in situations in which I've developed complex validation logic using the standard validator controls, only to realize I was unable to reuse any of it when I wanted to import data using a batch file or a Web Service. I'm working on an advanced validation class that would solve this limitation. If you have questions or ideas about how to implement such a solution, please contact me so we can share our ideas. With any luck, this functionality will be built into a future version of the .NET Framework.
The validator controls that ship with ASP.NET provide easy Web form validation that was unavailable to ASP classic developers. These controls eliminate the need for Web form developers to write validation code, especially client-side script, for most simple validation rules. Regular expressions provide a powerful way to match many kinds of string patterns, and you can use custom validation routines to handle complex validation logic that goes beyond string or number comparisons. Finally, commonly validated data fields can be packaged into composite controls that can be dragged and dropped as needed onto Web forms, to provide encapsulation and reuse of validation rules across different Web forms.
The files referenced in this article are available for download.
Steven A. Smith is president of ASPAlliance.com, a popular resource for the ASP and ASP.NET developer community. He also conducts training for ASPSmith.com. Steven is the author of ASP.NET By Example, a beginner's ASP.NET book full of working examples that can be viewed live at the book's Web site (http://aspauthors.com/aspnetbyexample/). Readers may reach Steven at mailto:[email protected].
Here's a quick overview of the available validator controls, what they do, and how to use them.
RequiredFieldValidator - Use this validator for any field that is required. It must be used for any required field in addition to other validator controls because this is the only validator that can determine when its ControlToValidate has a blank value.
CompareValidator - Use this validator to compare a field with a single fixed value or another control's value, by specifying a ValueToCompare or a ControlToCompare (but not both). Specify the kind of comparison to perform and data type of the control by setting the ValidationCompareOperator and ValidationDataType properties. This is also useful for validating that a value is a particular data type.
RangeValidator - Use this validator to specify that a value must fall within a particular range of values. RangeValidator supports the MinimumValue and MaximumValue properties in addition to a ValidationDataType property.
RegularExpressionValidator - Ensure user input matches one or more defined patterns using regular expressions and this validator. Set the regular expression that must match the ControlToValidate's value in this control's ValidationExpression property.
CustomValidator - When none of the above can do the job, write your own validation logic and wrap it up in a CustomValidator. Specify client-side validation functions with the ClientValidationFunction and wire up server-side validation by handling the ServerValidate event.
ValidationSummary - Displays a summary of all error messages on a page, either in HTML on the page itself, in a message box, or both. Specify its format by settings its DisplayMode property. Provide header text and specify the color of the text using the HeaderText and ForeColor properties, respectively. Toggle display of HTML results and message-box results by setting the ShowSummary and ShowMessageBox properties. Finally, designate whether the control should be updated using client-side script by setting its EnableClientScript property.