Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

ASP.NET Validation using Ajax

4.16/5 (9 votes)
3 Jan 2007CPOL5 min read 1   2K  
This article describes how to use Ajax to perform server side validation.

Introduction

Many times, it is desirable to perform JavaScript validation before submitting a page to the web server. For simple validations, client side JavaScript validation is sufficient. However, in complex scenarios, server side validation may be required and client side JavaScript will not suffice. In such scenarios, typically postbacks must be performed in order to do the server side validation. In many cases, the developer may not want the page to be posted back for validations, because the page state may be lost and the user experience may not be the smoothest. This is where AJAX comes in. The present article builds upon the power of AJAX to perform server side validations through the use of JavaScript without relying on postbacks.

Background

As mentioned before, the primary idea behind presenting this article is to show how to perform server side validations even when complex scenarios arise, while avoiding postbacks. The below control can be used as a centralized validation component, which can perform all validations for an ASP.NET web site.

Ajax Examples

Before getting into the details of how the validation works, we shall demonstrate how to make a simple AJAX call. For more information on Ajax, please see An Introduction to AJAX Techniques and Frameworks for ASP.NET.

In our examples, we will be using Ajax.NET component, developed by Michael Schwartz. We chose this component because it is very easy to implement and offers a great amount of flexibility.

The following settings need to be applied to the web.config in order to use Ajax.NET component successfully. For a detailed explanation of these settings, please see Michael Schwartz's web site Ajax.NET.

XML
<configSections>
    <sectionGroup name="ajaxNet">
      <!-- If you are using Microsoft .NET 1.1 please remove the two attributes 
      <!-- requirePermission and restartOnExternalChanges, they
      <!-- are only supported with .NET 2.0.-->
      <section name="ajaxSettings" 
               type="AjaxPro.AjaxSettingsSectionHandler,AjaxPro.2" 
      requirePermission="false" restartOnExternalChanges="true"/>
    </sectionGroup>
</configSections>
 
  <ajaxNet>
    <ajaxSettings>
     <urlNamespaceMappings useAssemblyQualifiedName="false">
     </urlNamespaceMappings>
     <jsonConverters></jsonConverters>
     <debug enabled="false" />
      <token enabled="false" sitePassword="password" />
    <oldStyle>
                <includeMsPrototype/>
    </oldStyle>
    </ajaxSettings>
  </ajaxNet>

  <location path="ajaxpro">
    <system.web>
      <httpHandlers>
        <add verb="*" path="*.ashx" 
             type="AjaxPro.AjaxHandlerFactory,AjaxPro.2"/>
      </httpHandlers>
    </system.web>
  </location>

Making a Simple Ajax Call

Create a simple web page with an HTML text box and a button control. Notice that the onclick event of the button calls the JavaScript function makeAjaxCall() which invokes Ajaxsample.AjaxTest Ajax method in code behind.

HTML
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Ajax.NET Sample</title>
    <script>
        function makeAjaxCall()
        {
            var retVal = AjaxSample.AjaxTest(document.form1.txtTest.value)
            alert(retVal.value)
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <!--Client Side text -->
        Enter value:<input type="text" id="txtTest"/>
        <!--<span class="code-comment">Client Side button -->
        <input type="button" id="btnTest" value="Test Ajax" 
               onclick="makeAjaxCall()" />
    </form>
</body>
</html></span>

The code behind class should be marked with <AjaxPro.AjaxNamespace("AjaxSample")> and the Ajax web method to be invoked should be marked with <AjaxPro.AjaxMethod()>. Also the page load event should register the namespace AjaxSample using AjaxPro.Utility.RegisterTypeForAjax(GetType(AjaxSample), Page). Below is the snippet of code showing the code behind.

VB.NET
<AjaxPro.AjaxNamespace("AjaxSample")> Partial Public Class AjaxSample
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, _
                            ByVal e As System.EventArgs) Handles Me.Load
        AjaxPro.Utility.RegisterTypeForAjax(GetType(AjaxSample), Page)
    End Sub

    <AjaxPro.AjaxMethod()> 
    Public Function AjaxTest(ByVal testParam As String) As String
        Return "You sent '" & testParam & "' as the testParam."
    End Function
End Class

Below is the output for the sample page created.

Simple Ajax output

Building the Validation Control

We create a web user control so that the same control can be reused across all the web pages in the application. The validations that will be supported by this control are defined inside a Enum ValidationType. This can be extended to support additional validations that are not covered.

VB.NET
Public Enum ValidationType
    RequiredField = 1
    DateRangeValidation = 4
    SingleDateValidation = 2
    CreditCardNumberValidation = 3
    DropdownlistValidation = 5
    DropdownlistRangeValidation = 11
    EmailValidation = 7
    PostalCodeValidation = 8
    URLValidation = 9
    TimeSlotRangeValidation = 10
    Numeric = 12
    HoursValidation = 13
    MinutesValidation = 14
    CompareValidation = 15
    TimeSlotValidation = 16
End Enum

Mark the controls class with <AjaxPro.AjaxNamespace("AjaxValidator")>, methods with <AjaxPro.AjaxMethod()> and finally register the namespace in the page load event with AjaxPro.Utility.RegisterTypeForAjax(GetType(Validator), Page) where Validator is the class name of the user control. This is similar to what we did in the earlier sample.

Create a structure RegisteredControlsDs and a private member of list class to contain the list of the web controls of type RegisteredControlsDs to be validated.

VB.NET
Private Structure RegisteredControlsDs
    Public control1 As UI.Control
    Public control1Desc As String
    Public control2 As UI.Control
    Public control2Desc As String
    Public type As ValidationType
    Public isRequired As Boolean

    Public Sub New(ByVal control1 As UI.Control,
                   ByVal control1Desc As String,
                   ByVal control2 As UI.Control,
                   ByVal control2Desc As String,
                   ByVal type As ValidationType,
                   ByVal isRequired As Boolean)
        Me.control1 = control1
        Me.control1Desc = control1Desc
        Me.control2 = control2
        Me.control2Desc = control2Desc
        Me.type = type
        Me.isRequired = isRequired
    End Sub

    Public Sub New(ByVal control1 As UI.Control,
                   ByVal control1Desc As String,
                   ByVal type As ValidationType,
                   ByVal isRequired As Boolean)
        Me.control1 = control1
        Me.control1Desc = control1Desc
        Me.control2 = control1
        Me.control2Desc = control1Desc
        Me.type = type
        Me.isRequired = isRequired
    End Sub
End Structure

Private _registeredControlsList As New List(Of
                                      RegisteredControlsDs)

The controls to be validated should be added to _registeredControlsList list. Depending on whether validation is on a single control or between two controls, one of the below two methods are used to register the controls respectively. For example, if it's comparison between two controls, then we use the second method. If it's a single control that needs to be validated for say Date, then we use the first method for registering the control.

VB.NET
//Method 1
Public Sub RegisterControl(ByVal control As UI.Control, _
                           ByVal controlDesc As String, _
                           ByVal type As ValidationType, _
                           ByVal isRequired As Boolean)
    _registeredControlsList _
        .Add(New RegisteredControlsDs(control, controlDesc, type, isRequired))
End Sub

//Method 2
Public Sub RegisterControls(ByVal control1 As UI.Control, _
                            ByVal control1Desc As String, _
                            ByVal control2 As UI.Control, _
                            ByVal control2Desc As String, _
                            ByVal type As ValidationType, _
                            ByVal isRequired As Boolean)
    _registeredControlsList_
              .Add(New RegisteredControlsDs(control1, control1Desc,_
               control2, control2Desc, type, isRequired))
End Sub

Once the controls are registered using the above methods, the next step is to create a ValidateControls method to validate the controls. Based on whether it is a single control validation or validation between two controls, ValidateControls calls one of the ValidateControl methods which is overloaded. These methods return a ValidationResult datastructure.

VB.NET
''' <summary>
''' This is the Ajax Method which is used to validate a set of UI
''' Controls.
''' </summary>
<AjaxPro.AjaxMethod()>
Public Function ValidateControls(ByVal ds As DataSet) As ValidationResult
    Dim retVal As New ValidationResult(True)
    Try
        Dim dt As DataTable = ds.Tables(0)
        Dim firstBadControl As String = String.Empty
        For Each dr As DataRow In dt.Rows
            Dim val1Name As String = dr("Control1Name")
                                         .ToString()
            Dim val1 As String = dr("Control1Value").ToString()
            Dim val1Desc As String = dr("Control1Description")
                                         .ToString()
            Dim val2Name As String = dr("Control2Name")
                                         .ToString()
            Dim val2 As String = dr("Control2Value").ToString()
            Dim val2Desc As String = dr("Control2Description")
                                         .ToString()
            Dim isreq As Boolean = Boolean.Parse(dr(
                      "IsRequired").ToString)
            Dim type As ValidationType = CType(dr(
                      "ValidationType"), ValidationType)
            Dim validationResult As ValidationResult
            If val1Name = val2Name Then
                validationResult = ValidateControl(val1Name,
                                   val1Desc, val1, isreq, type)
            Else
                validationResult = ValidateControl(val1Name,
                                   val1Desc, val1, val2Name,
                                   val2Desc, val2, isreq, type)
            End If
            If Not validationResult.Status Then
                retVal.Message &= validationResult
                                .Message & Environment.NewLine
                retVal.Status = False
                If firstBadControl = String.Empty Then
                     firstBadControl = val1Name
            End If
        Next
        retVal.InvalidControlName = firstBadControl
    Catch ex As Exception
        retVal.Message = "Ajax Exception:" & ex.ToString()
        retVal.Status = False
    End Try
    Return retVal
End Function

Finally, RegisterScript method builds the JavaScript dynamically based on the registered controls on the server side.

VB.NET
''' <summary>
''' Registers the Validation Script.
''' Javascript is generated based on which controls have been registered,
''' along with the Ajax call.
''' </summary>
Public Sub RegisterScript()
    Dim scriptCode As String = _
    "<script language="'javascript'" type='text/javascript'>" & _
    "function _validatePage()" & _
    "{" & _
    " try {" & _
    "var ds = new Ajax.Web.DataSet();" & _
    "var dt = new Ajax.Web.DataTable();" & _
    "dt.addColumn('Control1Name', 'System.String');" & _
    "dt.addColumn('Control1Value', 'System.String');" & _
    "dt.addColumn('Control1Description', 'System.String');" & _
    "dt.addColumn('Control2Name', 'System.String');" & _
    "dt.addColumn('Control2Value', 'System.String');" & _
    "dt.addColumn('Control2Description', 'System.String');" & _
    "dt.addColumn('IsRequired', 'System.Boolean');" & _
    "dt.addColumn('ValidationType', 'System.Int32');" & _
    "ds.addTable(dt);" & _
    "<DELTA>" & _
    "var res = AjaxValidator.ValidateControls(ds);" & _
    "if (res.value.Status == false) " & _
    " {alert(res.value.Message);" & _
    "document.getElementById(res.value.InvalidControlName).focus();" & _
    "return false;" & _
    "} else return true;" & _
    "} catch(ex) {alert('Validation Exception:' + ex.description); " &_
    "return false; }" & _
    "}" & _
    "</script>"

    Dim nl As String = Environment.NewLine
    Dim deltaCode As String = nl & "var <r> = {};" & nl & _
    "<r>.Control1Name = '<hidControlValue1>';" & nl & _
    "<r>.Control1Value = document.getElementById('<hidControlValue1>')." &_
    "value;" & nl & _
    "<r>.Control1Description = '<hidControlDesc1>';" & nl & _
    "<r>.Control2Name = '<hidControlValue2>';" & nl & _
    "<r>.Control2Value = document.getElementById('<hidControlValue2>')." &_
    "value;" & nl & _
    "<r>.Control2Description = '<hidControlDesc2>';" & nl & _
    "<r>.IsRequired = <isRequired>;" & nl & _
    "<r>.ValidationType = <type>;" & nl & _
    "dt.addRow(<r>);" & nl
    deltaCode = JsTryCatchIt(deltaCode, _
                           "Unable to find control <r>:<hidControlDesc1>")


    Dim codeBuilder As New StringBuilder
    For i As Integer = 0 To _registeredControlsList.Count - 1
        Dim snippet As String = deltaCode
        With _registeredControlsList(i)
            snippet = snippet.Replace("<r>", "r" & i)
            snippet = snippet.Replace("<hidControlDesc1>", .control1Desc)
            snippet = snippet.Replace("<hidControlDesc2>", .control2Desc)
            snippet = snippet.Replace("<isRequired>", _
                                     .isRequired.ToString.ToLower)
            snippet = snippet.Replace("<type>", _
                                      CType(.type, Integer).ToString())
            snippet = snippet.Replace("<hidControlValue1>",  _
                                      GetClientId(.control1))
            snippet = snippet.Replace("<hidControlValue2>",  _
                                      GetClientId(.control2))
        End With
        codeBuilder.Append(snippet)
    Next
    scriptCode = scriptCode.Replace("<DELTA>", codeBuilder.ToString)
    Page.ClientScript.RegisterStartupScript(Me.GetType, "validatorScript", _
                                            scriptCode)
    AppendToAttribute(_triggerControl, "onclick", _
                       "if(!_validatePage()) return false;")
End Sub

With this, the creation of validation user control is done. The below section describes how to use the validation control in our application pages, which is very easy.

Putting It All Together: Using the Validation User Control in a Web Page

Create a web form AjaxValidationSample.aspx and drag the validation user control into it. Add as many controls as needed for validation. In the page load event of the form, call the RegisterValidationControls() method. Inside RegisterValidationControls() (or a method of your choosing) you need to provide a Trigger Control which will trigger the validation. After that, call RegisterControl or RegisterControls methods in order to register the control(s) you want. At the end, call the RegisterScript method to render the Ajax JavaScript.

The following code shows the contents of AjaxValidationSample.aspx and its code behind:

HTML code:

HTML
<%@ Page Language="vb" AutoEventWireup="false" 
         CodeBehind="AjaxValidationSample.aspx.vb" 
         Inherits="AjaxValidation.AjaxValidationSample" %>
<%@ Register Src="Validator.ascx" TagName="Validator" TagPrefix="uc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Ajax Validation Sample</title>
</head>
<body>
    <form id="form1" runat="server">
        <table>
            <tr>
                <td colspan="2">
                    <uc1:Validator ID="Validator1" runat="server" />
                </td>
            </tr>
            <tr>
                <td>Email Address:</td>
                <td><asp:TextBox ID="txtEmail" runat="server" 
                         ToolTip="Email Address"></asp:TextBox></td>
            </tr>
            <tr>
                <td>Date Range:</td>
                <td><asp:TextBox ID="txtFrom" runat="server" 
                         ToolTip="From Date"/><asp:TextBox ID="txtTo" 
                         runat="server" ToolTip="To Date"/></td>
            </tr>
        </table>
        <asp:Button ID="btnSubmit" Text="Submit" runat="server"/>
    </form>
</body>
</html>

Code behind:

VB.NET
Public Partial Class AjaxValidationSample
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object,_
                            ByVal e As System.EventArgs) Handles Me.Load
        RegisterValidationControls()
    End Sub

    Private Sub RegisterValidationControls()
        Validator1.TriggerControl = btnSubmit
        Validator1.RegisterControl(txtEmail, ValidationType.EmailValidation, _
                                   True)
        Validator1.RegisterControls(txtFrom, txtTo, _
                                    ValidationType.DateRangeValidation, True)
        Validator1.RegisterScript()
    End Sub
End Class

That's it! At runtime, when the form loads, the JavaScript is loaded and the validations are applied. Below is the screen shot of the output once the submit button is clicked.

Simple Ajax output

Scope

The presented validation control is designed to handle single control validation and validation between two controls in batch mode. This means that you can validate 10 controls with one Ajax call.

Conclusion

We have seen how to create an extensible AJAX based validation user control. It is very easy to keep adding more types of validations to this control. All that one needs to do is define a new enum and provide the validation code and the validation control will do the rest. Hope this will be useful to someone. Happy coding!

History

  • Jan 2, 2007 - Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)