Adding Validatores to Page Validators

Here's an interesting aspect of page validation I came to realize just recently.

Adding Validator Declaratively

Suppose we have a text box, a required field validator, a validation summary and a submit button. Nothing crazy here.

<asp:ValidationSummary runat="server" />
<asp:TextBox ID="Name" runat="server" />

<asp:CustomValidator
runat="server"
ErrorMessage="Enter name"
OnServerValidate="cv_ServerValidate"
Display="None" />

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

The CustomValidator control here is added to the control tree early in the page life cycle. When the control is initialized, it adds itself to the Page.Validators collection:

protected internal override void OnInit(EventArgs e)
{
base.OnInit(e);
this.Page.Validators.Add(this);
}

The server-side validation method is very simple:

protected void cv_ServerValidate (
object source,
ServerValidateEventArgs args)
{
args.IsValid = (Name.Text.Trim().Length > 0);
}

Adding Validator Dynamically

What if we cannot add a validator declaratively and therefore have to create and add it dynamically? The Page class has a publicly available collection Validators which seems to be a good fit.

protected override void OnInitComplete (EventArgs e)
{
base.OnInitComplete (e);

CustomValidator cv = new CustomValidator();
cv.ServerValidate +=
new ServerValidateEventHandler (cv_ServerValidate);
cv.Display = ValidatorDisplay.None;
cv.ErrorMessage = "Enter name";
Page.Validators.Add (cv);
}

Note the last line above. If you happen to also specify a JavaScript function to call upon validation on the client, it won't fire. For that matter, this validator won't render any HTML at all!

This actually did happen. We bought a suite of controls from a major vendor. Their souped-up combo box control didn't offer any validation, so I decided to subclass it and tack on a custom validator. This way I could do some validation both on the client and the server… except that my custom validator failed to render any HTML, although its server-side validation logic worked! This really had me scratching my head. If a validator control adds itself to the Page.Validators collection, why can't I do it myself?

Reflector revealed that Page.Validators is simply a wrapper around an ArrayList with no special logic. And then it dawned on me:

My custom validator wasn't in the control tree, which is why it didn't go through the normal control life cycle and therefore had no render phase. Basically, I was adding it to an ArrayList maintained by the Page class, but it was never added to the control tree.

Conclusion

From this saga I learned that you shouldn't touch Page.Validators unless you're developing your own validator control. If you absolutely need to create a validator on the fly, make sure you add it to page controls one way or another.

Share

Twitter Delicious Facebook Digg Stumbleupon Favorites