Use a CustomValidator for Complex Validation

The validator controls in ASP.NET are very useful and have established a very good framework upon which to build. Validating user input used to be very difficult but now most of your validation requirements can be satisfied by simply add one of the validator controls to your web page. Very nice! But there are some situations in which the existing controls just don't meet your needs. Thankfully, the CustomValidator control exists which makes it simple to write some complex validation.

You may have come across your first need for the CustomValidator when you wanted to validate a control only if a specific condition existed. None of the other validators can do that. So let's start by laying out an example such as this and then we'll build our code.

Say you are trying to get some information from the user about how they found your site. You add a DropDownList to the page with several different common options. But since you can't cover every possible way you want to create the last option as "Other" and let them enter a value in a textbox. Well you don't want a value to be required in the textbox unless they selected "Other". So how do you go about setting up a CustomValidator for this. First I will lay out some simple markup.

1<asp:DropDownList ID="FoundMethod" runat="server">

2<asp:ListItem Value="1" Text="Google" />

3<asp:ListItem Value="2" Text="Discussion Forum" />

4<asp:ListItem Value="3" Text="Other" />

5</asp:DropDownList>

6<asp:TextBox ID="OtherText" runat="server" />

7<br />

8<br />

9<asp:Button ID="Submit" runat="server" Text="Submit" />

A very simple setup. We've got the DropDownList with the last option "Other", a TextBox for the text of "Other" and a Button to submit to the server. Next let's add in the declaration of the CustomValidator.

1<asp:DropDownList ID="FoundMethod" runat="server">

2<asp:ListItem Value="1" Text="Google" />

3<asp:ListItem Value="2" Text="Discussion Forum" />

4<asp:ListItem Value="3" Text="Other" />

5</asp:DropDownList>

6<asp:TextBox ID="OtherText" runat="server" />

7<asp:CustomValidator ID="OtherTextRequired" runat="server" ControlToValidate="OtherText" ErrorMessage="Please enter how you found us when selecting &quot;Other&quot;" OnPreRender="OtherTextRequired_PreRender" OnServerValidate="OtherTextRequired_ServerValidate" ValidateEmptyText="true" />

8<br />

9<br />

10<asp:Button ID="Submit" runat="server" Text="Submit" />

Two things I want you to take note of. The OnServerValidate attribute and the ValidateEmptyText attribute. The rest of the attributes are the same for the other validators so I won't address those.

The OnServerValidate function is where you will write your code to validate on the server. Your method must accept an object as its first parameter and an instance of ServerValidateEventArgs. The ServerValidateEventArgs instance contains two important properties in it. First, is "Value" which is a read-only property and it provides you the value of the control which we specified in the ControlToValidate attribute. The other property is IsValid which allows you to pass a value to the framework to indicate whether validation was successful or not.

ValidateEmptyText is also important here. This property tells the control whether or not it should continue with validation if a value isn't entered in the control it is to validate. As you're probably aware all of the other validators except for RequiredFieldValidator don't perform validation if no value exists. Well in our case since we're going to be testing whether the user entered a value or not then we want it to validate empty text. Since the default value is false I set the value to true for this example.

Moving right along let's take a look at how we would setup our server validation code.

1protected void OtherTextRequired_ServerValidate( object sender, ServerValidateEventArgs e )

2{

3// If the radiobuttonlist value is 3 then the user

4// selected "Other" and we will validate their input.

5if (this.FoundMethod.SelectedValue == "3")

6{

7// If there is text in the textbox then the value is valid.

8if (e.Value.Length > 0)

9{

10e.IsValid = true;

11}

12 

13// Otherwise no value was entered and it is invalid.

14else

15{

16e.IsValid = false;

17}

18}

19 

20// Otherwise if the user selected another value

21// then we will just set the IsValid value to true.

22else

23{

24e.IsValid = true;

25}

26}

Let's step through this code. At line 5 we test whether the user selected the "Other" option. If they did we will continue with validation. We check to see if the length of the value is greater than zero. Greater than zero indicates that a value was entered and therefore it is valid. A length of zero is invalid as you can see from lines 8-17. Lastly, we add an else clause which says if any other option was selected then validation succeeded. Test it out at this point.

This was simple enough to setup in the server-side code. But we don't want to stop here. It's important to setup client-side validation if at all possible. Validation performed on the client is faster and reduces the number of trips that must be made to the server. Writing out the javascript is fairly straight-forward except for one part. How do you identify the id of the DropDownList. In line 5 of the server-side code we reference that control very easily but it takes a little more extra work with javascript. One way to do it is to view your page in the browser, view the source and determine what the id is of the control that way. But I think you'll find this method I'm about to propose a lot more simple.

Have you ever created a web page before that had validation controls on it and viewed the rendered source using your browser? You've probably noticed several lines of javascript at the very bottom. There were several lines that look like they were assigning values to a class. What we want to do is use this same pattern to pass the value we need. And to do this we'll use a method called RegisterExpandoAttribute of the ClientScriptManager class. Every page has a property called "ClientScript" which is an instance of the ClientScriptManager class. Take a look at my example below and then we'll step through each part.

1protected void OtherTextRequired_PreRender( object sender, EventArgs e )

2{

3this.ClientScript.RegisterExpandoAttribute( this.OtherTextRequired.ClientID, "foundMethodInput", this.FoundMethod.ClientID );

4}

There's four points I want you to take note of. First, we're adding this code in the CustomValidator's PreRender event. This isn't a requirement but I personally consider it a best practice. Here's why. It's important that this line of code isn't executed unless the CustomValidator will actually be rendered. The PreRender event will not be raised unless this is the case. So, if at any other location in our code we toggle the Visible property of the validator we don't have to worry about turning this line of code on or off. Second, the first argument we're passing is the CustomValidator's ClientID. It's important not to pass the ID. It's the ClientID that will be necessary as client script only works with client id's. Third, the second argument passed is the name of the property to add to the object that will be passed as the sender in our client script. Lastly, we'll be passing the ClientID of our DropDownList. That is how we can ensure that the proper value is passed to our client script.

Conclusion

There you have it. How to implement a CustomValidator. Let's review some of the points you need to keep in mind when using this great control.

  • Use a CustomValidator only when the other validators do not meet your requirements.
  • Set the value of the ValidateEmptyText property to true only if no value in the input will affect the validity.
  • Be sure to setup server-side validation control and attach your method to the CustomValidator's ServerValidate event.
  • Setup client-side validation if at all possible to enhance the user's experience.
  • Any information needed in your client-side script that is not readily available at design-time should be passed through the sender argument by using the RegisterExpandoAttribute method of the page's ClientScript property.
New Comment

Info

Your name and comment are required. Enter an email and url if your prefer. Your email will not be displayed.

Published: 10/5/2008
View Code:
Email
 

.NET Advisor