Implementing custom validation in ASP.NET with the CustomValidator class


by Jason Salas, KUAM.COM
February 17, 2003

 

Past editions:

Building a newsletter management system in ASP.NET with C#: Part 2

Program a time-coding application to calculate read-times

Building a newsletter management system in ASP.NET with C#: Part 1

A simple document management system in ASP with XML and XSLT

Password-protect your Web work

Error Handling in VBScript

Creating a banner ad rotation system

The Web-safe color palette for developers

Time-saving Windows shortcuts

Analyzing your site's traffic logfiles

Technologies Used:

Level of Difficulty

Hello fellow code warriors!

If you recall, in newsletters-aspnetcsharp.htm, we learned how to enforce better quality control in your Web software projects by the use of validation. To do this, we used a variety of ASP.NET’s Validation Web server controls to set criteria and test the accuracy of the data, and return error messages to the Web browser if data entered within the WebForm’s elements did not match these criteria.

You’ll also recall that I used a combination of validation controls to ensure the form was valid, meaning the user filled out their first name, last name and e-mail address, and then tested to make sure the user’s e-mail address was in the proper format. I also wrote a custom subroutine that checked if none of the checkboxes in the form were checked, and if so, returned an error message to the user letting her know that at least one newsletter had to be signed up for.

The only thing that’s less than optimal about this second validation technique is that the browser is forces to make a call back to the server to do the validation, and performance-wise, this roundtrip adds unnecessary overhead to your app. Also, from a user-friendliness standpoint, this forces the user to have to click on the “Back” button to select at least one choice, which is a minor inconvenience, but an inconvenience nonetheless.

One developer wrote me and asked if there was an alternate way to do this, using similar validation controls:

Hi Jason,
I’m curious as to whether a developer would be able to use a custom validation routine and go all the way back to the server? Couldn’t it just be done at the client and be faster? I know there’s server-side validation that can be done in ASP.NET, but would simple JavaScript be any better? Thanks!

Johann
Stuttgart, Germany

The answer? Absolutely! I actually did this intentionally to show you the various ways that you can accomplish the same thing in ASP.NET (OK, I’m lying…I was lazy). Perhaps the best thing about the .NET Framework is that while it provides comprehensive functionality through it’s really, really big library of pre-shipped classes, it’s completely extensible. If you think you can do something more efficiently, with less code, or more suitable to your application, or you just don’t like the way Microsoft’s defined how to get something done, and you always roll you own solution.

In this installment of “Dev Dungeon” we’re going to look at the ASP.NET CustomValidator server control, and implement it to enforce our business rule, requiring that at least one newsletter must be subscribed to.

I’ve developed a simple WebForm that emulates part of the form we looked at in Part 1. Looking at our page-level code in the form itself, you can see that I’ve laid out four server controls, namely a Label, CheckBoxList, a Button, and something new – our CustomValidator control. Contrary to the other validation controls that ASP.NET provides, the CustomValidator allows you to define programming logic in your WebForm’s <SCRIPT> blocks (like we’re doing here), or in a code-behind file, like we saw in Part 2.

When using a CustomValidator on a page, a developer uses the CustomValidator class and writes methods to ensure the validity of a form, and then sets the OnServerValidate and ClientValidationFunction properties. This not unsurprisingly allows you to test for validation at the server and client levels, respectively. In the case of the former, any arguments are passed to the function through the ServerValidateEventArgs parameter of the method’s signature. In the case of the latter, client-side JavaScript is typically used to validate the form’s contents upon submission. Most of the other properties inherent to validation controls, such as ErrorMessage, Display, and Text. See the .NET Framework documentation or http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWebUIWebControlsCustomValidatorClassTopic.asp for more on the CustomValidator class.
 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<%@ Page Language="C#" ClientTarget="ie5" EnableViewState="False" EnableSessionState="False" Trace="False" Debug="False" autoeventwireup="False" %>
<script runat="server">

    public void Fill_HT(object sender, EventArgs e)
    {
        Hashtable ht = new Hashtable();
        ht.Add("Mindy Fothergill","mindy@kuam.com");
        ht.Add("Sabrina Salas","sabrina@kuam.com");
        ht.Add("Rachel Taimanao","rachel@kuam.com");
        ht.Add("Ken Wetmore","ken@kuam.com");
        ht.Add("Trina San Agustin","trina@kuam.com");
        ht.Add("Zita Taitano","zita@kuam.com");
        ht.Add("Fredalynn Mortera Hecita","fredalynn@kuam.com");
        ht.Add("Brant McCreadie","brant@kuam.com");
        ht.Add("Keoki Sablan","keoki@kuam.com");
        ht.Add("Jason Salas","jason@kuam.com");
    
        chkboxPeeps.DataSource = ht;
        chkboxPeeps.DataTextField = "key";
        chkboxPeeps.DataValueField = "value";
        chkboxPeeps.DataBind();
    }
    
    private void User_Choice(object sender, ServerValidateEventArgs e)
    {
        int counter = 0;
    
        for(int i=0;i<chkboxPeeps.Items.Count;i++)
        {
            if(chkboxPeeps.Items[i].Selected)
            {
                counter++;
            }
    
            e.IsValid = (counter == 0) ? false : true;
        }
    }
    
    public void ValidateForm(object sender, EventArgs e)
    {
        if(Page.IsValid)
        {
            lblChoice.Text = "Message is authentic!";
        }
        else
        {
            lblChoice.Text = "You have failed validation.";
        }
    }

</script>
<html>
    <head>
    <title>Custom vadliation with the CustomValidation Web server control</title>
    </head>
    <body>
        <form runat="server">
            <asp:Label id="lblChoice" runat="server"/>
            <br/><br/>
            <asp:CheckBoxList id="chkboxPeeps" OnInit="Fill_HT" runat="server"/>
            <asp:CustomValidator id="customvalidation" runat="server" display="dynamic" text="You need to select at least one of the choices to be valid" OnServerValidate="User_Choice"/>           
            <asp:Button id="btnSubmit" Text="Validate!" OnClick="ValidateForm" runat="server"/>
        </form>
    </body>
</html>


User_Choice method
So, getting back to our WebForm, we’ve defined two methods – the private method User_Choice starting on line 24 and the public ValidateForm starting on line 39. The first is wired to our CustomValidator control through the aforementioned OnServerValidate event on line 61, and the latter is wired to our Button’s OnClick event on line 62. Essentially, User_Choice iterates through the CheckBoxList control, and tests to see if any of the boxes have been checked. As you learned in Part 1, we’ve dynamically populated our CheckBoxList control at design-time, so there’s no real way at run-time to know just how many elements there are.

However, we know that each checkbox rendered to the page as an HTML <input type=”text”> element can be accessed programmatically in our code as part of an array, through the CheckBoxList’s Items collection. We use a simple for… loop in lines 28-36 that checks if the item is checked (through the Selected property), and if so, increment an integer variable we introduce, counter. This gives us a running count of how many choices the user has selected.

Now, we use C#’s ternary operator on line 35 to evaluate the numeric value of counter, and if it happens to be greater than 0, this means that the user checked at least one of the boxes. In such case, we assign a value of false to the boolean IsValid property, and if not, assign it as true.


ValidateForm method
In our second method, we simply test the value of the IsValid property in line 41. Because this is wired to the Button’s OnClick event, this cannot be prematurely executed before User_Choice, ensuring the quality control we’re after. If the value is true, we return a rather simple congratulatory message to our Label’s Text property, and if not, we do the opposite. Notice how I’ve declaratively used some of the various properties of the CustomValidator control to generate an error message presented to the user.

Figure 1 shows the WebForm when browsing to it, before submission. Figure 2 shows the WebForm properly validated, and Figure 3 shows an invalid form submission.


Figure 1: the ASP.NET WebForm prior to submission
 


Figure 2: the ASP.NET WebForm successfully validated
 


Figure 3: the ASP.NET WebForm unsuccessfully validated
 


So why just not use client-side JavaScript???

The question of whether or not to use a simple JavaScript is a good one, and very logical. Why spend the time writing two server-side methods when I could just embed a JavaScript scriptblock to ensure

Using the CustomValidator server control in the way we’ve just done integrates better with the life-cycle of your page. I openly recommend playing with various implementations of custom server-side validation routines, and the .NET Framework makes it very easy to roll your own. However, if you’re of the programming flow

That we’ve populated our CheckBoxList control dynamically might make this tough for a client-side JavaScript routine, because we’d have to know ahead of time the specific values of the ID and Name attributes of the HTML Checkbox elements to access them, if we were to use the DHTML document object model (DOM), which would normally be the case. This is significantly easier using server-side logic. The .NET Framework automatically assigns each element in a WebForm a unique ID and/or Name, eliminating the chance for problems that would arise from clashes. However, this still doesn’t make it any easier to program against them, not knowing what they’ll be at design-time.

It’s not impossible – it would just take more work.

The best thing about the CustomValidator is that it gives you the option to use server- events and/or client-side logic to ensure a WebForm is valid. You get the integration with the naming system used by the .NET Framework and customizability within the life-cycle of the page with server-side logic, plus the quick response of a client-side JavaScript subroutine or function.

Best case scenario? I’d use both, in a professional setting.

So now that we’ve seen how to implement a custom validation rule, here’s your homework. Re-develop Part 1 of our tutorial and implement the CustomValidator server control instead of the generic routine we used originally. I think you’ll be pleased with the reduction in code – and with the results.

Happy programming!
</jason>