ASP.NET CAPTCHA Ajax Validation C# Code Sample

The ASP.NET CAPTCHA Ajax validation sample project shows how to properly perform Ajax CAPTCHA validation using built-in BotDetect CAPTCHA client-side functionality, which doesn't require any 3rd party Ajax frameworks.

First Time Here?

Check the BotDetect ASP.NET WebForms Captcha Quickstart for key integration steps.

Ajax CAPTCHA validation improves the user experience by reducing CAPTCHA validation response time, giving users much faster feedback about the validation result.

Client-side validation is not secure by itself (it can be bypassed trivially), so the sample also shows how the protected form action must always be secured by server-side CAPTCHA validation as well.

In case of any Ajax errors or timeouts, the sample simply falls back to full form posting and server-side CAPTCHA validation.

Download the BotDetect ASP.NET CAPTCHA Component and run this sample

Visual Studio 2012 / .NET 4.5

By default, the .NET 4.5 C# version of the ASP.NET Captcha Ajax Validation sample project is installed at:
C:\Program Files\Lanapsoft\BotDetect 3 CAPTCHA Component\Asp.Net\v4.5\WebApp\CaptchaAjaxValidationSample\CSharp

You can also run it from the BotDetect Start Menu:
Programs > Lanapsoft > BotDetect 3 CAPTCHA Component > ASP.NET > DotNET 4.5 Web Applications > Run

The Visual Studio 2012 / .NET 4.5 source has no essential differences from the Visual Studio 2010 / .NET 4.0 source.

Visual Studio 2010 / .NET 4.0

By default, the .NET 4.0 C# version of the ASP.NET Captcha Ajax Validation sample project is installed at:
C:\Program Files\Lanapsoft\BotDetect 3 CAPTCHA Component\Asp.Net\v4.0\WebApp\CaptchaAjaxValidationSample\CSharp

You can also run it from the BotDetect Start Menu:
Programs > Lanapsoft > BotDetect 3 CAPTCHA Component > ASP.NET > DotNET 4.0 Web Applications > Run

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.
aspx.cs" Inherits="_Default" %>

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

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
  <title>BotDetect ASP.NET CAPTCHA Ajax Validation Sample</title>
  <link type="text/css" rel="Stylesheet" href="StyleSheet.css" />
</head>
<body>
  <form id="form1" runat="server">
  <h1>BotDetect ASP.NET CAPTCHA Ajax Validation Sample</h1>
  <fieldset>
    <legend>CAPTCHA Validation</legend>
    <p class="prompt"><label for="CaptchaCodeTextBox">Retype the 
    characters from the picture:</label></p>
    <BotDetect:Captcha ID="SampleCaptcha" runat="server" />
    <div class="validationDiv">
      <asp:TextBox ID="CaptchaCodeTextBox" runat="server"></asp:
      TextBox>
      <asp:Button ID="ValidateCaptchaButton" runat="server" />
      <asp:Label ID="CaptchaCorrectLabel" runat="server" 
      CssClass="correct"></asp:Label>
      <asp:Label ID="CaptchaIncorrectLabel" runat="server" 
      CssClass="incorrect"></asp:Label>
    </div>
  </fieldset>
  <script type="text/javascript">
    function OnCaptchaValidate() {
      // update display and disable the button
      document.getElementById('CaptchaCorrectLabel').style.display = 
      'none';
      document.getElementById('CaptchaIncorrectLabel').style.display = 
      'none';
      
      document.getElementById('ValidateCaptchaButton').disabled = true;
      document.getElementById('ValidateCaptchaButton').value = 
      'Validating...';
    }
    
    function OnCaptchaCorrect() {
      // update display
      document.getElementById('CaptchaCorrectLabel').innerHTML = 
      'Correct! (client)';
      document.getElementById('CaptchaCorrectLabel').style.display = 
      'inline';
      
      document.getElementById('CaptchaIncorrectLabel').style.display = 
      'none';
      
      // automatically proceed to server-side validation
      document.getElementById('ValidateCaptchaButton').disabled = 
      false;
      document.getElementById('ValidateCaptchaButton').focus();
      document.getElementById('ValidateCaptchaButton').click();
    }
    
    function OnCaptchaIncorrect() {
      // update display and enable the button for re-tries
      document.getElementById('CaptchaCorrectLabel').style.display = 
      'none';
      
      document.getElementById('CaptchaIncorrectLabel').innerHTML = 
      'Incorrect! (client)';
      document.getElementById('CaptchaIncorrectLabel').style.display = 
      'inline';
      
      document.getElementById('ValidateCaptchaButton').disabled = 
      false;
      document.getElementById('ValidateCaptchaButton').value = 
      'Validate';
    }
            
    function OnAjaxError() {
      // fall back to server-side validation
      document.getElementById('ValidateCaptchaButton').disabled = 
      false;
      document.getElementById('ValidateCaptchaButton').focus();
      document.getElementById('ValidateCaptchaButton').click();
    }
  </script>
  </form>
</body>
</html>

The Captcha Ajax validation workflow is controlled by the four client-side methods defined on the page: OnCaptchaValidation, OnCaptchaCorrect, OnCaptchaIncorrect and OnAjaxError.

Handlers for the four Ajax-related client-side events will be automatically called by the Validate() function call at appropriate stages of the Ajax Captcha validation workflow.

Main concerns of these handlers are displaying the validation result, disabling multiple consecutive button clicks while Ajax validation is in progress, and handling Ajax errors and timeouts.

Details of the Ajax implementation are encapsulated in BotDetect source for easier use. They involve making an Ajax request at a special endpoint in the Captcha handler, and processing the returned JSON result. You do not need to concern yourself with such details, but can use the supplied Validate() function as is.

Default.aspx.cs

using System;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_PreRender(object sender, EventArgs e)
    {
        // initial page setup
        if (!IsPostBack)
        {
            // set control text
            ValidateCaptchaButton.Text = "Validate";

            // these messages are shown only after validation
            CaptchaCorrectLabel.Attributes.CssStyle["display"] = 
            "none";
            CaptchaIncorrectLabel.Attributes.CssStyle["display"] = 
            "none";
        }

        // setup client-side input processing
        SampleCaptcha.UserInputClientID = CaptchaCodeTextBox.ClientID;
        ValidateCaptchaButton.OnClientClick = String.Format("return {0}
        .Validate();", SampleCaptcha.CaptchaId);

        // client-side custom event handlers
        string script = @"
BotDetect.RegisterCustomHandler('PreAjaxValidate', OnCaptchaValidate);
BotDetect.RegisterCustomHandler('AjaxValidationFailed', 
OnCaptchaIncorrect);
BotDetect.RegisterCustomHandler('AjaxValidationPassed', 
OnCaptchaCorrect);
BotDetect.RegisterCustomHandler('AjaxValidationError', OnAjaxError);";
        
        this.Page.ClientScript.RegisterStartupScript(this.GetType(), 
        "BotDetectCustomEventHandlers", script, true);

        if (IsPostBack)
        {
            // validate the Captcha to check we're not dealing with a 
            bot
            string code = CaptchaCodeTextBox.Text.Trim().ToUpper();
            bool isHuman = SampleCaptcha.Validate(code);
            CaptchaCodeTextBox.Text = null; // clear previous user 
            input

            if (isHuman)
            {
                CaptchaCorrectLabel.Attributes.CssStyle["display"] = 
                "inline";
                CaptchaIncorrectLabel.Attributes.CssStyle["display"] = 
                "none";
                CaptchaCorrectLabel.Text = "Correct (server)!";
            }
            else
            {
                CaptchaCorrectLabel.Attributes.CssStyle["display"] = 
                "none";
                CaptchaIncorrectLabel.Attributes.CssStyle["display"] = 
                "inline";
                CaptchaIncorrectLabel.Text = "Incorrect (server)!";
            }
        }
    }
}

During page setup, we register the four client-side methods defined before as BotDetect Ajax event handlers, and set BotDetect Ajax validation (calling the Validate() function exposed by the BotDetect client-side object interface) as the button ClientClick handler.

During page submission, we perform Captcha validation as usual, since Ajax validation is simply a client-side usability improvement which doesn't affect server-side processing at all. Label text and display style is slightly adjusted from the basic sample, to make tracking the combined client- and server-side Captcha validation workflow easier.

Web.config

<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.
  NetConfiguration/v2.0">
  <system.web>
    <httpHandlers>
      <!-- Register the HttpHandler used for BotDetect Captcha 
      requests -->
      <add verb="GET" path="BotDetectCaptcha.ashx" 
        type="BotDetect.Web.CaptchaHandler, BotDetect"/>
    </httpHandlers>
    <!-- Register a custom SessionIDManager for BotDetect Captcha 
    requests -->
    <sessionState mode="InProc" cookieless="AutoDetect" timeout="20" 
      sessionIDManagerType="BotDetect.Web.CustomSessionIdManager, 
      BotDetect"/>
    <!-- Session state is required for BotDetect storage; you can also 
    turn if off globally and only enable for BotDetect-protected pages 
    if you prefer -->
    <pages enableSessionState="true">
      <controls>
        <!-- Register the BotDetect tag prefix for easier use in all 
        pages -->
        <add assembly="BotDetect" namespace="BotDetect.Web.UI" 
          tagPrefix="BotDetect"/>
      </controls>
    </pages>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Design, Version=4.0.0.0, Culture=neutral,
        PublicKeyToken=B03F5F7F11D50A3A"/>
      </assemblies>
    </compilation>
    <trace enabled="false" localOnly="true"/>
    <httpCookies httpOnlyCookies="true"/>
    <trust level="Medium" originUrl=""/>
    <authentication mode="None"/>
    <customErrors mode="RemoteOnly"></customErrors>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <handlers>
      <!-- Register the HttpHandler used for BotDetect Captcha 
      requests (IIS 7.0+) -->
      <remove name="BotDetectCaptchaHandler"/>
      <add name="BotDetectCaptchaHandler" 
        preCondition="integratedMode" verb="GET" 
        path="BotDetectCaptcha.ashx" 
        type="BotDetect.Web.CaptchaHandler, BotDetect"/>
    </handlers>
  </system.webServer>
</configuration>

There are several BotDetect-related changes in the web.config file, including Captcha HttpHandler registration, ASP.NET Session state configuration, and BotDetect tag prefix registration.

Visual Studio 2008 / .NET 3.5

By default, the .NET 3.5 C# version of the ASP.NET Captcha Ajax Validation sample project is installed at:
C:\Program Files\Lanapsoft\BotDetect 3 CAPTCHA Component\Asp.Net\v3.5\WebApp\CaptchaAjaxValidationSample\CSharp

You can also run it from the BotDetect Start Menu:
Programs > Lanapsoft > BotDetect 3 CAPTCHA Component > ASP.NET > DotNET 3.5 Web Applications > Run

The Visual Studio 2008 / .NET 3.5 source has no essential differences from the Visual Studio 2010 / .NET 4.0 source.

Visual Studio 2005 / .NET 2.0

By default, the .NET 2.0 C# version of the ASP.NET Captcha Ajax Validation sample project is installed at:
C:\Program Files\Lanapsoft\BotDetect 3 CAPTCHA Component\Asp.Net\v2.0\WebApp\CaptchaAjaxValidationSample\CSharp

You can also run it from the BotDetect Start Menu:
Programs > Lanapsoft > BotDetect 3 CAPTCHA Component > ASP.NET > DotNET 2.0 Web Applications > Run

The Visual Studio 2005 / .NET 2.0 source has no essential differences from the Visual Studio 2010 / .NET 4.0 source.