Introduction
ASP.NET supplies a few validator controls to ensure that user input data will match application needs. Most of them check if control data is not empty or entered data matches specific data type etc. In real world ASP.NET applications, we very often need to check inserted value against database. ASP.NET supplies a CustomValidator
which can be useful for this task. CustomValidator
uses server-side events where programmer may write code to check whatever or not control value meets business rules. Of course, this kind of validation needs submit. In this article, I will provide an alternate way to solve this problem.
Background
Since the beginning of my career as a web programmer, I wondered if there is any way to get data from web server to HTML page which is open on client machine. This problem is solved in many ways including the use of IFRAME
or XML. For me, it was very useful to read this great article: Client Side Validation Using the XMLHTTPRequest Object By Jonathan Zufi, to understand how this things work and how I can use XMLHTTPRequest
in ASP.NET server control.
Using the code
In a few sentences, I'll explain how my validator works: I inherit my validator from CustomValidator
. CustomValidator
has ClientValidateFunction
property which may be useful when developers want to validate on client. I insert my function which makes XMLHTTPRequest
to SAME PAGE with a few parameters in QueryString. I override onLoad()
event. Inside it, I check by QueryString parameters if I should raise custom event (called ClientValidate
).
using System;
using System.Data;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.IO;
using System.Web;
using System.Design;
using System.Drawing.Design;
using System.Collections.Specialized;
namespace Gilat
{
[DefaultProperty("Text"), ToolboxData("<{0}:GilatValidator
runat=server></{0}:GilatValidator>")]
public class GilatValidator : System.Web.UI.WebControls.CustomValidator
{
const string XMLHTTPRequestScript = @"
<script language='javascript'>
//GilatControlsUtils.RegisterXMLHTTPRequestScript
function doXMLHTTPRequest(Url)
{
var oXMLHTTP = new ActiveXObject(""Microsoft.XMLHTTP"");
oXMLHTTP.open(""POST"", Url, false);
try
{
oXMLHTTP.send();
return oXMLHTTP.responseText;
}
catch(e)
{
alert(""XMLHTTPRequest failed"");
return """";
}
}
</script>";
string GilatValidatorClientScript = @"
<script language='javascript'>
function {0}Validate(source, arguments)
{{
var sURL = ""{1}__serverSideRequest=true&__source="" + source.id;
//add ControlToValidate
if(source.controltovalidate != undefined)
{{
sURL += ""&ControlToValidateValue="" +
document.all(source.controltovalidate).value;
}}
var ControlsToValidate = source.ControlsToValidate;
if(ControlsToValidate != undefined)
{{
var arrControlsToValidate = ControlsToValidate.split("";"");
for(var i=0; i<arrControlsToValidate.length; i++)
{{
var Control = document.all(arrControlsToValidate[i]);
if(Control)
{{
sURL += ""&"" + Control.id + ""="" + Control.value;
}}
}}
}}
arguments.IsValid = (doXMLHTTPRequest(sURL) == ""true"");
}}
</script>";
private string _ControlsToValidate;
public string ControlsToValidate
{
get
{
return _ControlsToValidate;
}
set
{
_ControlsToValidate = value;
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender (e);
if(ControlsToValidate != string.Empty)
this.Attributes.Add("ControlsToValidate", ControlsToValidate);
this.ClientValidationFunction = this.ID + "Validate";
string Url = Page.Request.Url.ToString();
if(Page.Request.QueryString.ToString() != string.Empty)
Url += "&";
else
Url += "?";
Page.RegisterClientScriptBlock("GilatValidatorScript",
string.Format(GilatValidatorClientScript, ID, Url));
if(!Page.IsClientScriptBlockRegistered("XMLHTTPRequestScript"))
{
Page.RegisterClientScriptBlock("XMLHTTPRequestScript",
XMLHTTPRequestScript);
}
}
public event
System.Web.UI.WebControls.ServerValidateEventHandler ClientValidate;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
HttpRequest Request = this.Page.Request;
if(Request.QueryString["__serverSideRequest"] == "true" &&
Request.QueryString["__source"] == this.ID)
{
Page.Response.Clear();
ServerValidateEventArgs ServerValidateE = new
ServerValidateEventArgs(Request.QueryString["ControlToValidateValue"],
false);
OnCallbackValidation(ServerValidateE);
if(ServerValidateE.IsValid)
Page.Response.Write("true");
Page.Response.End();
}
}
protected virtual void OnCallbackValidation(ServerValidateEventArgs e)
{
if (ClientValidate != null)
{
ClientValidate(this, e);
}
}
}
}
Points of Interest
A few important issues:
- Events order:
ClientValidation
event happens after PageLoad
event.
- Inside
ClientValidation
event, you can't use control values, because I do not pass ViewState.
- Property
ControlsToValidate
is the only way to pass control values to server.
ControlsToValidate
includes any Control ID delimited by ";".
Inside ClientValidate
event, you may access these values like:
string MyComboValue = Request.QueryString[MyCombo.ID];
You can still use args.Value
(if you use ControlToValidate
) and args.IsValid
like in normal ServerValidate
event. See it in the attached sample project. Of course, validator will work only on browsers with XMLHTTPRequest
installed. Another thing: if you're having an exception inside the ClientValidation
event, you can't see it on page. But you may enable Application trace and then check it from there.