AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=699&pId=-1
Solving the Challenges of ASP.NET Validation
page
by Peter Blum
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 156377/ 230

I have been working with the ASP.NET validator controls commercially almost since ASP.NET 1.0 was released. In the process, I created a number of my own validators based on the System.Web.UI.WebControls.BaseValidator class for my customers to use. I was never happy with the flexibility of the overall validation framework. So I built my own validation framework, Professional Validation And More, and have been focused on the challenges developers have faced with the original validators so that my software is the best solution available. In particular, I regularly answer questions posted on the forums at www.asp.net. This article will identify the common questions raised and offer answers.

The ASP.NET validators lack features that are common real-world situations. For so many situations, the answer is to abandon the existing validator and write your own using a CustomValidator. Also, developers are limited by the client-side JavaScript of the ASP.NET validators and cannot enhance their user interface to provide nice tricks like changing the background color of the field with the error or prompting with an alert. I've found that custom code and hacks are the rule instead of the exception. Microsoft has too and has provided a few enhancements in ASP.NET 2.0 which I'll address. For a list of the 27 limitations I've found with the ASP.NET validators, go to www.peterblum.com/vam/valmain.aspx.

Setting up ASP.NET Validation on a Domain

With ASP.NET 1.x, whenever you create a new domain or deploy to a new domain, there are two common issues developers face. They both involve client-side validation.

  1. Client-side validation does not work at all.
  2. Client-side validation works, but when you click a submit button, the button fails to post back.

ASP.NET 2.0 developers can skip this section.

Client-side validation does not work at all

Each domain requires a folder called /aspnet_client/system_web/[.net version] with two script files: WebUIValidation.js for client-side validation and SmartNav.js for smart navigation. (ASP.NET 2.0 no longer uses the /aspnet_client folder. Instead, it embeds the scripts directly into the ASP.NET assemblies so you cannot have these problems.)

You must create this folder with these files. The folder must be specific to the .NET version running on the server. For example, if you develop on ASP.NET 1.0 and deploy to a hosted server running ASP.NET 1.1, the [.net version] folder will be different.

This should be done:

  • When you create a new domain.
  • When you deploy to a domain on a different server for the first time.
  • When that server has a new version of ASP.NET 1.x installed (including service packs).

There are two ways to do this.

1. The recommended method is to run this command:

aspnet_regiis.exe –c
from [windows]\microsoft.net\framework\[.net version]
If your site is hosted, most hosts will do this for you. Otherwise, use the second method:

2. Create the folders and copy the files.

Note: Only do this from the server where your domain is located because you need to get files specific to the version of ASP.NET running on that server.

Copy all of the files from:
[windows]\microsoft.net\framework\[.net version]\ASP.NETClientFiles
to:
/aspnet_client/system_web/[.net version]
The [.net version] folder must be identical in both cases.

Buttons do not submit

Developers have found that a submit button suddenly stops working after installing ASP.NET 1.1 Service Pack 1. Unfortunately, Microsoft introduced a bug in SP 1 that causes this problem. They have documented it with a solution in Knowledge Base article 889877. However, that doesn't always work.

Paul Wilson and Thomas Freudenberg have posted their solutions on blogs. Here is their recommendation:

  1. Open the WebUIValidation.js file in a text editor. The file is located in
    [domain root]/aspnet_client/system_web/1_1_4322
    .
  2. Locate the function ValidatorCommonOnSubmit.
  3. Change it by adding return event.returnValue; as the last line:
function ValidatorCommonOnSubmit() {
   event.returnValue = !Page_BlockSubmit;
   Page_BlockSubmit = false;
   return event.returnValue;
}

Careful! Javascript is case sensitive!

Creating a Page with ASP.NET Validation

Don’t depend on client-side validation

This is probably the most important thing you can learn from this entire article: Always write code for server-side validation. Too many people test their web pages on Internet Explorer which provides client-side validation automatically. So they never see a need to test the server-side validation. Simply put, if you don't write some validation code on the server side, you will not have server-side validation protecting you from bad data.

Here's why:

  • ASP.NET 1.x only supports client-side validation on DHTML browsers. That means Internet Explorer for Windows and Macintosh. Firefox, Mozilla, Safari, and most other browsers use the DOM standard which is not supported by ASP.NET 1.x. So a portion of your users will always be lacking the client-side validation.

    Microsoft has addressed this limitation in ASP.NET 2.0 as it now supports the DOM browsers. ASP.NET 1.x users can use my Professional Validation And More or a free replacement called DOM Validators from Paul Glavine to get DOM support.
  • Javascript can be turned off. In fact, hackers who want to use SQL Injection and Cross-site Scripting attacks will turn it off to launch their attacks. After all, validation is your first defense against illegal data.

It's easy to support server side validation. Microsoft has done most of the work for you.

1. For the submit controls -- Buttons, LinkButtons, ImageButtons, and even the HtmlControl buttons -- they made the OnClick method automatically call Page.Validate() which validates all enabled controls on the page. All you have to do is add one statement inside your Click event method before executing code:

[C#]
protected void Submit_OnClick(object pSender, EventArgs e)
{
   if (Page.IsValid)
   {
      // your code here
   }
}
[VB]
Protected Sub Submit_OnClick(ByVal pSender As Object, ByVal e As EventArgs)
   If Page.IsValid Then
      ' your code here
   End If
End Sub

2. Other controls can post back. For example, a menu control or toolbar button. These controls have their own post back event handlers. They do not call Page.Validate() for you. So you need to make your post back event method first calls Page.Validate() and then tests that Page.IsValid is true.

[C#]
protected void MenuCmd1_OnClick(object pSender, EventArgs e)
{
   Page.Validate();
   if (Page.IsValid)
   {
      // your code here
   }
}
[VB]
Protected Sub MenuCmd1_OnClick(ByVal pSender As Object, ByVal e As EventArgs)
   Page.Validate()
   If Page.IsValid Then
      ' your code here
   End If
End Sub
When to Validate

There are several situations that require you to disable one or more validators, or to request validation where it's not normally done:

  • Some buttons do not save anything, such as a Cancel button. You need to prevent the button from validating.
  • There are two or more buttons on the page and each has its own list of validators to fire.
  • A validator should be evaluated based on some condition on the page, such as the value of another control.
  • AutoPostBack should validate to avoid a post back if the page has errors.

Preventing a button from validating

Here is one of the most overlooked features of ASP.NET Validation. I see developers ask about this several times a week on the www.asp.net forums. Now you don't have to be one of them.

When you have a Cancel button or any other button that should never validate anything, simply set its CausesValidation property to false. The Button, LinkButton, ImageButton and the HtmlControl buttons all have this property.

<asp:Button id="CancelBtn" runat=server Text="Cancel" CausesValidation="false" />

Several buttons associated with their own validators

Suppose you have a login or search section on a page that also has some data entry fields. Each section has its own submit button with validators. When you setup validators on all the fields and click one submit button, the validators from the other section report errors, preventing the form from submitting.

Microsoft recognized that ASP.NET needs to handle this case has introduced Validation Groups in ASP.NET 2.0. (My Professional Validation And More already has Validation Groups.) To use validation groups, create a group name for each section. Then assign that name to the ValidationGroup property found on ASP.NET 2.0 buttons and validators in that section. It's very simple.

What happens if you have ASP.NET 1.x? You will have to use server-side validation when the page is submitted to validate the individual validators associated with the submit button:

  1. Set the submit control's CausesValidation property to false.
  2. In the Click event method for each submit button, call the Validate() method on each validator that is in the section. Then test that the IsValid property of each validator in the section is true. For example:
[C#]
RequiredFieldValidator1.Validate();
RequiredFieldValidator2.Validate();
if (RequiredFieldValidator1.IsValid && RequiredFieldValidator2.IsValid)
{
   // your code here
}
[VB]
RequiredFieldValidator1.Validate()
RequiredFieldValidator2.Validate()
If RequiredFieldValidator1.IsValid And RequiredFieldValidator2.IsValid Then
   ' your code here
End If

Now this design prevents client-side validation from occuring when the user clicks submit. (Validation will still occur as the user changes individual fields.) Some users have attempted to create client-side code that runs when the user clicks on the submit button and sets each validator’s enabled attribute to false or true. That way, the client-side validation will still run, but will skip the validators that are not enabled. This is a bad design as it leaves those validators disabled. If there was an error, the user would continue to edit the form with some of the validators now disabled.

Enabling validators

Microsoft designed ASP.NET validators so you can write server-side code to solve the shortcomings of client-side code. One of those shortcomings is a very common situation: you have a validator that should not validate unless there is a specific condition on the page. Examples include a checkbox is marked, another textbox has data, and the data entry field is enabled. In my product, I solved this by providing each validator with a property called Enabler where you specify the rule that enables the validator.

When using Microsoft's validators, there are several ways to do this.

1. Use server-side validation. Call individual validator's Validate() method in the Click event method after determining if the validator should fire.

a. Turn off client-side validation on each validator that needs to be disabled by setting EnableClientScript to false.

b. Set CausesValidation to false on the submit button.

c. In the Click event method, call the Validate() method on each validator but add logic to skip any validator that should not validate. Then test the IsValid property on each validator for true before saving.

Here is an example where RequiredFieldValidator2 should be enabled only when CheckBox1 is checked. RequiredFieldValidator1 will always validate:

[C#]
RequiredFieldValidator1.Validate();
if (CheckBox1.Checked)
   RequiredFieldValidator2.Validate();
bool vIsValid = true;
if (!RequiredFieldValidator1.IsValid)
   vIsValid = false;
if (vIsValid && CheckBox1.Checked && !RequiredFieldValidator2.IsValid)
   vIsValid = false;
if (vIsValid)
{
   // your code here
}
[VB]
RequiredFieldValidator1.Validate()
If CheckBox1.Checked Then
   RequiredFieldValidator2.Validate()
End If
Dim vIsValid As Boolean = True
If Not RequiredFieldValidator1.IsValid Then
   vIsValid = False
End If
If vIsValid And CheckBox1.Checked And Not RequiredFieldValidator2.IsValid Then
   vIsValid = False
End If
If vIsValid Then
   ' your code here
End If

2. Use a CustomValidator. This will let you preserve client-side validation by creating some client-side code for validation. The problem is that you end up writing the same logic already created in the existing validators. While developing the same logic as in the RequiredFieldValidator is easy (remember to trim spaces!), try writing a CompareValidator for dates. (As the author of a popular DatePicker control, I can assure you that date parsing in Javascript is not easy!)

There's one other challenge here: you will be writing JavaScript and using DHTML. If you lack experience in these technologies, this becomes a much bigger task.

See the .NET documentation topic, CustomValidator Overview, for details on using a CustomValidator. Be sure to write code for both client and server-side validation.

AutoPostBack and validation

In ASP.NET 1.x, the AutoPostBack features of data entry controls do not validate before submitting. If they did, the page could avoid an unnecessary trip to the server.

ASP.NET 2.0 introduces two new properties of data entry controls: CausesValidation and ValidationGroup. These are exclusively used when AutoPostBack is true. When CausesValidation is true, it will perform client-side validation using the validation group defined in the ValidationGroup property.

Be careful in using this feature because all validators of a Validation Group are evaluated. So any controls that have not been filled in yet will have their RequiredFieldValidator fired, preventing post back.

MessageBoxes and Validation

I frequently see questions about how to show an alert with error messages when the user submits the page, or how to get a confirmation message to work with validation on the page.

Alert on submit

To show an alert on submit, add the ValidationSummary control and set its ShowMessageBox property to true. If you don't want to show the ValidationSummary control on the page itself, set its ShowSummary property to false.

<asp:ValidationSummary id="Summary1" runat=server ShowMessageBox="true" ShowSummary="false" />

Be aware that the message box requires client-side code support. So any validator that only has server-side code will not appear in the message box.

Confirm message

To add a confirm message, you add the following javascript to the onclick event of the button:

if (!confirm('[your message here]')) return false;

In ASP.NET 2.0, assign that string to the button's OnClientClick property.

In ASP.NET 1.1, assign that string to the button's onclick attribute in Page_Load, like this:

Button1.Attributes.Add("onclick", "if (!confirm('[your message here]')) return false;")

In ASP.NET 1.0, there are some tricks to doing this but it's quite complex.

Features of the Validator Controls

There are only five validator controls offered by Microsoft and so many more cases that developers have discovered. (When designing my own product, I came up with 25 separate validators to cover the many validation rules found on web pages.) Generally this means developers have to use the CustomValidator to get the job done. Before you choose that, here are a few features developers often overlook about the existing validators and the CustomValidator.

The CompareValidator can check the format of dates and numbers

Every week, I see several people asking how to validate the date entered into a textbox. Some are already looking for the right regular expression to use with the RegularExpressionValidator.

Microsoft provides a validator to do this, but they don't make it obvious. Use the CompareValidator with its Operator property set to DataTypeCheck and its Type property set to the desired format. This works much better than regular expressions because it actually checks for a valid date number, not just a format. The regular expression couldn't tell you that 2/31/2004 is an invalid date. This validator can.

<asp:CompareValidator id="DateValidator" runat=server Operator="DataTypeCheck" 
   Type="Date" ControlToValidate="DateTextBox" ErrorMessage="Bad format" />

Validators support for globalization

When you accept date and numeric entries in textboxes on the web, you are working with a world-wide audience whose date and number formats differ from your server's format.

Microsoft developed the System.Globalization.CultureInfo class to describe the formats of dates, numbers, currencies, and text. The RangeValidator and CompareValidator use this object to support globalization.

Every page has a CultureInfo object assigned to the current thread in System.Threading.Thread.CurrentThread.CurrentUICulture. It gets its value from several places:

  • You may set it programmatically in Page_Load, Page_Init, or Page.InitializeCulture (ASP.NET 2.0 only) method of the page, or the Application_BeginRequest method of Global.asax.
System.Threading.Thread.CurrentThread.CurrentUICulture = 
  System.Globalization.CultureInfo.CreateSpecificCulture("id-ID")
  • You may set it in the <@ Page> declaration as the Culture property:
<%@ Page Culture="id-ID" %>
  • You set it for your entire site in web.config's <globalization> section:
<globalization culture="id-ID" />

Where I've used id-ID above, you should use the appropriate culture. They are listed here.

Using validators with DropDownLists and ListBoxes

Validators look at the text value of the control they are validating. DropDownLists and ListBoxes have text values. They are assigned when you add ListItems like this:

<asp:DropDownList [properties] runat="server">
   <asp:ListItem Value="[here is the value]">name</asp:ListItem>
</asp:DropDownList>

Use the RequiredFieldValidator to detect an item for "No Selection" like this:

1. Add an item indicating no selection to the DropDownList with a specific value, like "No Selection":

<asp:ListItem Value="NoSelection">--- No Selection --</asp:ListItem>

2. Assign the value to the InitialValue property of the RequiredFieldValidator. For example:

<asp:RequiredFieldValidator id="RequiredFieldValidator1" runat=server 
   ControlToValidate="DropDownList1" InitialValue="NoSelection"
   ErrorMessage="Required" />

Make sure the InitialValue is a case-sensitive match to the ListItem's Value.

Use the CompareValidator to determine if a single item is selected or not selected. Just determine the value of that item and assign it to the ValueToCompare property. Then set the Operator to Equal (for selected) or NotEqual (for not selected). In this example, the ListItem whose value is "Blue" must not be selected:

<asp:compareValidator id="NotBlue" runat=server ControlToValidate="DropDownList1" 
   ValueToCompare="Blue" Operator="NotEqual" Type="String" ErrorMessage="Do not select blue" />

Making the CustomValidator support blank textboxes

As you work with the Validator controls, you will learn that only the RequiredFieldValidator will evaluate a blank textbox. Developers who build CustomValidators often want to evaluate blank textboxes too. You can! Do not assign anything to the ControlToValidate property. Instead, write your evaluation function to get the value of the textbox directly. For example, in server-side code, if your TextBox is called TextBox1, you can get the value from TextBox1.Text.

Summary

By now, you have probably made several discoveries about the Microsoft validators that will help you build more secure sites with less effort. Microsoft's validator controls are still very simplistic, lacking in many evaluation rules and ways to get the user's attention that you find on high quality sites. For these, you still must develop custom code and hacks, or use a third-party product like Professional Validation And More.

Peter has also created Digging Deeper into ASP.NET Validation, a free, two-part training video on www.dnrtv.com and associated traing materials. In the tutorial, you will learn:

  1. Four important but commonly overlooked features of the ASP.NET Validators
  2. Requiring that at least one textbox has text
  3. Enabling validators based on the state of other controls
  4. Situations too complex for Validation Groups
  5. Determining if at least one checkbox is marked in a GridView

Please visit http://www.peterblum.com/dnrtv.aspx for links to the show and the training materials.


Product Spotlight
Product Spotlight 

©Copyright 1998-2020 ASPAlliance.com  |  Page Processed at 2020-07-05 10:38:24 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search