I was browsing through the microsoft.public.dotnet.framework.aspnet.webcontrols newsgroup tonight and stumbled upon a post by a fellow named Haz, who asked:
I am building a web custom control and I need to make sure that the file
/aspnet_client/system_web/{framework version}/WebUIValidation.js
is included in the page.
Is there any way to force the page to make sure that it is included?
My understanding is that Haz is wanting to be able to programmatically determine from his custom control whether or not the page has the client-side, JavaScript include in there for the WebUIValidation.js file. I assume he is wanting to have his control's markup somehow interact with this file, so he needs to determine if it's been added or not.
The WebUIValidation.js file, as you know, contains client-side JavaScript functions for client-side validation. It is automatically injected into a page when:
-
-
I fired up Reflector to sneek a peak at the System.Web.UI.WebControls.BaseValidator class, which is the class from which all validation Web controls are derived. Initially I looked at the RegisterValidationCommonScript() method, which is responsible for squirting out the JavaScript include file reference. As I've waxed on about in my article Working with Client-Side Script, the Page class contains assorted methods for injecting client-side script. When adding such script, you have to give it a key; there are corresponding methods to determine whether or not a script block with a specified key name has been added.
My initial though, then, was to simply check if a script block with key ValidatorIncludeScript had been registered (as this is the key name the BaseValidator uses when adding the JavaScript include reference). However, the RegisterValidationCommonScript() method, from which this script is injected, doesn't happen until the PreRender stage of the Page's lifecycle. If you can afford to wait this long, then this is the definitive approach. To Haz I say this: in your control, you could override the OnPreRender() method, check to see if ValidatorIncludeScript has been added, and, if not, add it yourself. (You can get the necessary code straight out of the BaseValidator class; in fact, I'd recommend you just copy and paste the code for the RegisterValidationCommonScript() method into your control's OnPreRender() method.
But what if you need to determine if the WebUIValidation.js script will be added? That is, what if you need to know in, say, the Load event if this script will be added. Well, the Page class has a public Validator property, which is a collection of the validators on the page. The BaseValidator class has a method definition for the OnInit() method, which runs during the Initialization stage. In this method, the validator control adds itself to the Page's Validator collection. So, you can simply check if Page.Validator.Count > 0 - if so, there are one or more validators on the page and the WebUIValidation.js script will be emitted. ... Right?
Well, maybe not. Remember that the the WebUIValidation.js script is emitted if there are any validators on the page and if the browser visiting the page is an uplevel browser. Huh. The question, then, is how do validators determine if a browser is uplevel or not? As I discuss in Client-Side Validation in DownLevel Browsers, the BaseValidator class has a DetermineRenderUplevel() method that does the following check: a browser is considered “uplevel” if it has an MS DOM version of 4 or greater.
Note: By default, ASP.NET only consideres IE 4.0+ uplevel; however, you can enhance your Web application and specify that other browsers (FireFox, Mozilla, etc.) should be considered uplevel. The problem here - as I discuss in Client-Side Validation in DownLevel Browsers - is that the actual script emitted by WebUIValidation.js is non-standards compliant, and only works with IE... Bummer, eh? There are work-arounds, as I discuss in my article.
So, if you need to know prior to the PreRender stage whether or not the WebUIValidation.js script will be emitted, you can determine if it will if both Page.Validators.Count > 0 and Request.Browser.MSDomVersion.Major >= 4.
When digging around, one thing concerned me: what if I add a dynamic validation control - what happens then? Is the Page.Validator collection updated accordingly? The answer is, Yes. Whenever you add a control to another control's Controls property, it takes the added control through the Initialization and LoadViewState stages, at minimum, and through the Load stage as well, if the parent control is past the Load stage itself. So, Page.Validators will be updated accordingly, but the one caveat is that if you are checking at, say, the custom control's Load stage, and another control in the hierarchy later adds a validator dynamically, the first control will “miss” that the WebUIValidation.js script will be emitted. (I hope that doesn't sound too confusing.)