BotDetect ASP.NET 2.0 Ajax CAPTCHA VB.NET Code Sample

The BotDetect ASP.NET CAPTCHA Ajax code sample shows how to make the BotDetect CAPTCHA validation work inside an ASP.NET 2.0 Ajax UpdatePanel. It can be used when migrating BotDetect-protected forms to ASP.NET Ajax.

The Captcha control code is the same whether you are using .NET Framework 2.0 + the ASP.NET Ajax Extensions 1.0 or the .NET Framework 3.5 (where the Ajax extensions code has been integrated with the core framework). The only difference between the ASP.NET Ajax versions is in the web.config files, so there are two separate versions of this sample included in the BotDetect installation.

Sample Project Location

By default, this sample project is installed at
C:\Program Files\Lanapsoft\BotDetect\ASP.NET 2.0\v2.0\Samples\VBNetBotDetectAspNet20AjaxDemo\ and VBNetBotDetectAspNet35AjaxDemo.

You can also run it from the Start Menu:
Programs > Lanapsoft > BotDetect > ASP.NET 2.0 > v2.0 > Samples > VB.Net BotDetect ASP.NET Ajax CAPTCHA Sample (.NET 2.0) and VB.Net BotDetect ASP.NET Ajax CAPTCHA Sample (.NET 3.5).

Default.aspx

Full Source Code Listing

<%@ Page Language="VB" AutoEventWireup="true" 
    CodeFile="Default.aspx.vb" Inherits="_Default" %>

<%@ Register Assembly="Lanap.BotDetect" Namespace="Lanap.BotDetect" 
    TagPrefix="BotDetect" %>

<!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>BotDetect Demo</title>
    <link type='text/css' rel='Stylesheet' href="StyleSheet.css" />
</head>
<body>
    <form id="form1" runat="server">
    <fieldset id="Preview">
    <legend><span id="PreviewLegend">CAPTCHA Preview</span></legend>
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
        <asp:UpdatePanel ID="CaptchaUpdatePanel" runat="server" 
            UpdateMode="Conditional">
            <ContentTemplate>
                <div>
                    <div id="PromptDiv">
                        <span id="Prompt">Type the characters 
                            you see in the picture</span>
                    </div>
                    <div id="CaptchaDiv">
                        <BotDetect:Captcha id="SampleCaptcha" 
                            runat="server" />
                    </div>
                </div>
                <div id="ValidationDiv">
                    <asp:TextBox id="CodeTextBox" runat="server">
                    </asp:TextBox>
                    <asp:Button id="ValidateButton" runat="server">
                    </asp:Button> 
                    <asp:Label id="MessageCorrectLabel"
                        runat="server"></asp:Label> 
                    <asp:Label id="MessageIncorrectLabel" 
                        runat="server"></asp:Label> 
                </div>
            </ContentTemplate>
        </asp:UpdatePanel>
        </fieldset>
        <div id="Note">
        <span>NOTE: the Trial version will use "LANAP" instead of a 
            random code in 50% of renderings.</span>
    </div>
    </form>
</body>
</html>

Explanation

Lines required to add the BotDetect CAPTCHA control to the ASP.NET form and make it validate using Ajax partial postbacks are bold. To use the <BotDetect:Captcha> control, we must first register the Lanap.BotDetect.dll assembly using the <%@Register %> directive.

The form also contains an <asp:TextBox> for the user input, an <asp:Button> to submit the page, and a pair of <asp:Label> controls which are used to show the CAPTCHA validation result.

The <asp:ScriptManager> control is needed to enable ASP.NET Ajax functionality, and the whole CAPTCHA validation part of the page has been placed inside an <asp:UpdatePanel> with the UpdateMode="Conditional" setting, allowing partial postbacks and redrawing only of the part of the form contained within the UpdatePanel <ContentTemplate>.

Default.aspx.vb

Full Source Code Listing

Partial Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_PreRender(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles MyBase.PreRender

        ' initial page setup
        If (Not IsPostBack) Then

            'set control text
            ValidateButton.Text = "Validate"
            MessageCorrectLabel.Text = "Correct!"
            MessageIncorrectLabel.Text = "Incorrect!"

            'these messages are shown only after validation
            MessageCorrectLabel.Visible = False
            MessageIncorrectLabel.Visible = False
        End If
				
        // clear user input on Reload button clicks
        string scriptTemplate = @"
          function LBD_ClearUserInput() {{
            var LBD_textBox = document.getElementById('{0}');
            if(LBD_textBox) {{
              LBD_textBox.value = '';
            }}
          }}
          LBD_RegisterHandler('PreReloadCaptchaImage', 
            LBD_ClearUserInput);
        ";
        string script = String.Format(scriptTemplate, 
          CodeTextBox.ClientID);
					
        if (!Page.ClientScript.IsStartupScriptRegistered(
            "CaptchaReloadClearInput"))
        {
          Page.ClientScript.RegisterStartupScript(this.GetType(), 
            "CaptchaReloadClearInput", script, true);
        }

        // automatically lowercase user input
        CodeTextBox.Attributes.Add("onkeyup", _
            "this.value = this.value.toLowerCase();")

        If (IsPostBack) Then
            'validate the input code, and show the 
            'appropriate message 
            Dim code As String = CodeTextBox.Text.Trim().ToUpper()

            If (SampleCaptcha.Validate(code)) Then
                MessageCorrectLabel.Visible = True
                MessageIncorrectLabel.Visible = False
            Else
                MessageCorrectLabel.Visible = False
                MessageIncorrectLabel.Visible = True
            End If

            'clear previous user code input
            CodeTextBox.Text = ""
        End If

    End Sub

End Class

Explanation

There is no extra code required for Ajax validation in the form codebehind, since the UpdatePanel partial postback is processed the same as a full postback (regarding the ASP.NET page life-cycle), except that changes to controls outside the <ContentTemplate> are effectively discarded.

Web.config (.NET 2.0)

Full Source Code Listing

<?xml version="1.0"?>
<configuration>
  <configSections>
    <sectionGroup name="system.web.extensions" 
      type="System.Web.Configuration.SystemWebExtensionsSectionGroup, 
      System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, 
      PublicKeyToken=31bf3856ad364e35">
      <sectionGroup name="scripting" 
        type="System.Web.Configuration.ScriptingSectionGroup, 
        System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35">
        <section name="scriptResourceHandler" type="System.Web.
          Configuration.ScriptingScriptResourceHandlerSection, 
          System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, 
          PublicKeyToken=31bf3856ad364e35" requirePermission="false" 
          allowDefinition="MachineToApplication"/>
        <sectionGroup name="webServices" type="System.Web.
          Configuration.ScriptingWebServicesSectionGroup, 
          System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, 
          PublicKeyToken=31bf3856ad364e35">
          <section name="jsonSerialization" type="System.Web.
            Configuration.ScriptingJsonSerializationSection, 
            System.Web.Extensions, Version=1.0.61025.0, 
            Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
            requirePermission="false" allowDefinition="Everywhere"/>
          <section name="profileService" type="System.Web.
            Configuration.ScriptingProfileServiceSection, 
            System.Web.Extensions, Version=1.0.61025.0, 
            Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
            requirePermission="false" 
            allowDefinition="MachineToApplication"/>
          <section name="authenticationService" type="System.Web.
            Configuration.ScriptingAuthenticationServiceSection, 
            System.Web.Extensions, Version=1.0.61025.0, 
            Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
            requirePermission="false" 
            allowDefinition="MachineToApplication"/>
        </sectionGroup>
      </sectionGroup>
    </sectionGroup>
  </configSections>
  <system.web>
    <pages>
      <controls>
        <add tagPrefix="asp" namespace="System.Web.UI" 
          assembly="System.Web.Extensions, Version=1.0.61025.0, 
          Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      </controls>
    </pages>
    <!-- 
      Set compilation debug="true" to insert debugging 
      symbols into the compiled page. Because this 
      affects performance, set this value to true only 
      during development.
    -->
    <compilation debug="false">
      <assemblies>
        <add assembly="System.Web.Extensions, Version=1.0.61025.0, 
          Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        <add assembly="System.Design, Version=2.0.0.0, 
          Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
      </assemblies>
    </compilation>
    <httpHandlers>
      <remove verb="*" path="*.asmx"/>
      <add verb="*" path="LanapCaptcha.aspx" 
        type="Lanap.BotDetect.CaptchaHandler, Lanap.BotDetect"/>
      <add verb="*" path="*.asmx" validate="false" 
        type="System.Web.Script.Services.ScriptHandlerFactory, 
        System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35"/>
      <add verb="*" path="*_AppService.axd" validate="false" 
        type="System.Web.Script.Services.ScriptHandlerFactory, 
        System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35"/>
      <add verb="GET,HEAD" path="ScriptResource.axd" 
        type="System.Web.Handlers.ScriptResourceHandler, 
        System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35" validate="false"/>
    </httpHandlers>
    <httpModules>
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, 
        System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35"/>
    </httpModules>
    <sessionState mode="InProc" cookieless="AutoDetect" timeout="20" 
      sessionIDManagerType="Lanap.BotDetect.Persistence.
      CustomSessionIDManager, Lanap.BotDetect" />
    <customErrors mode="On" defaultRedirect="~/Error.html" />
  </system.web>
  <system.web.extensions>
    <scripting>
      <webServices>
        <!-- Uncomment this line to customize maxJsonLength and add a 
          custom converter -->
        <!--
        <jsonSerialization maxJsonLength="500">
          <converters>
            <add name="ConvertMe" 
              type="Acme.SubAcme.ConvertMeTypeConverter"/>
          </converters>
        </jsonSerialization>
        -->
        <!-- Uncomment this line to enable the authentication service. 
          Include requireSSL="true" if appropriate. -->
        <!--
        <authenticationService enabled="true" 
          requireSSL = "true|false"/>
        -->
        <!-- Uncomment these lines to enable the profile service. 
          To allow profile properties to be retrieved and modified 
          in ASP.NET AJAX applications, you need to add each property 
          name to the readAccessProperties and writeAccessProperties 
          attributes. -->
        <!--
        <profileService enabled="true"
          readAccessProperties="propertyname1,propertyname2"
          writeAccessProperties="propertyname1,propertyname2" />
        -->
      </webServices>
      <!--
      <scriptResourceHandler enableCompression="true" 
        enableCaching="true" />
      -->
    </scripting>
  </system.web.extensions>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules>
      <add name="ScriptModule" preCondition="integratedMode" 
        type="System.Web.Handlers.ScriptModule, System.Web.Extensions, 
        Version=1.0.61025.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35"/>
    </modules>
    <handlers>
      <remove name="WebServiceHandlerFactory-Integrated"/>
      <add name="ScriptHandlerFactory" verb="*" path="*.asmx" 
        preCondition="integratedMode" 
        type="System.Web.Script.Services.ScriptHandlerFactory, 
        System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35"/>
      <add name="ScriptHandlerFactoryAppServices" verb="*" 
        path="*_AppService.axd" preCondition="integratedMode" 
        type="System.Web.Script.Services.ScriptHandlerFactory, 
        System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35"/>
      <add name="ScriptResource" preCondition="integratedMode" 
        verb="GET,HEAD" path="ScriptResource.axd" 
        type="System.Web.Handlers.ScriptResourceHandler, 
        System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, 
        PublicKeyToken=31bf3856ad364e35"/>
      <remove name="LanapCaptchaHandler" />
      <add name="LanapCaptchaHandler" preCondition="integratedMode" 
        verb="*" path="LanapCaptcha.aspx" 
        type="Lanap.BotDetect.CaptchaHandler, Lanap.BotDetect" />
    </handlers>
  </system.webServer>
</configuration>

Explanation

This version of the Web.config file is the one you will use with .NET Framework 2.0 + ASP.NET Ajax Extensions 1.0. Lines necessary for BotDetect CAPTCHA to function properly have been bold, other lines are all standard values generated by Visual Studio 2005 with ASP.NET Ajax Extensions 1.0 installed.

Web.config (.NET 3.5)

Full Source Code Listing

<?xml version="1.0"?>
<configuration>
  <configSections>
    <sectionGroup name="system.web.extensions" 
      type="System.Web.Configuration.SystemWebExtensionsSectionGroup, 
      System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
      PublicKeyToken=31BF3856AD364E35">
      <sectionGroup name="scripting" type="System.Web.
        Configuration.ScriptingSectionGroup, System.Web.Extensions, 
        Version=3.5.0.0, Culture=neutral, 
        PublicKeyToken=31BF3856AD364E35">
        <section name="scriptResourceHandler" type="System.Web.
          Configuration.ScriptingScriptResourceHandlerSection, 
          System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
          PublicKeyToken=31BF3856AD364E35" requirePermission="false" 
          allowDefinition="MachineToApplication"/>
        <sectionGroup name="webServices" type="System.Web.
          Configuration.ScriptingWebServicesSectionGroup, 
          System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
          PublicKeyToken=31BF3856AD364E35">
          <section name="jsonSerialization" type="System.Web.
            Configuration.ScriptingJsonSerializationSection, 
            System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
            PublicKeyToken=31BF3856AD364E35" requirePermission="false" 
            allowDefinition="Everywhere"/>
          <section name="profileService" type="System.Web.
            Configuration.ScriptingProfileServiceSection, 
            System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
            PublicKeyToken=31BF3856AD364E35" requirePermission="false" 
            allowDefinition="MachineToApplication"/>
          <section name="authenticationService" type="System.Web.
            Configuration.ScriptingAuthenticationServiceSection, 
            System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
            PublicKeyToken=31BF3856AD364E35" requirePermission="false" 
            allowDefinition="MachineToApplication"/>
          <section name="roleService" type="System.Web.Configuration.
            ScriptingRoleServiceSection, System.Web.Extensions, 
            Version=3.5.0.0, Culture=neutral, 
            PublicKeyToken=31BF3856AD364E35" requirePermission="false" 
            allowDefinition="MachineToApplication"/>
        </sectionGroup>
      </sectionGroup>
    </sectionGroup>
  </configSections>
  <system.web>
    <pages>
      <controls>
        <add tagPrefix="asp" namespace="System.Web.UI" 
          assembly="System.Web.Extensions, Version=3.5.0.0, 
          Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add tagPrefix="asp" namespace="System.Web.UI.WebControls" 
          assembly="System.Web.Extensions, Version=3.5.0.0, 
          Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      </controls>
    </pages>
    <!--
    Set compilation debug="true" to insert debugging
    symbols into the compiled page. Because this
    affects performance, set this value to true only
    during development.
    -->
    <compilation debug="true">
      <assemblies>
        <add assembly="System.Design, Version=2.0.0.0, 
          Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
        <add assembly="System.Core, Version=3.5.0.0, 
          Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <add assembly="System.Web.Extensions, Version=3.5.0.0, 
          Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Xml.Linq, Version=3.5.0.0, 
          Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <add assembly="System.Data.DataSetExtensions, 
          Version=3.5.0.0, Culture=neutral, 
          PublicKeyToken=B77A5C561934E089"/>
      </assemblies>
    </compilation>
    <httpHandlers>
      <remove verb="*" path="*.asmx"/>
      <add verb="*" path="LanapCaptcha.aspx" 
        type="Lanap.BotDetect.CaptchaHandler, Lanap.BotDetect"/>
      <add verb="*" path="*.asmx" validate="false" 
        type="System.Web.Script.Services.ScriptHandlerFactory, 
        System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
        PublicKeyToken=31BF3856AD364E35"/>
      <add verb="*" path="*_AppService.axd" validate="false" 
        type="System.Web.Script.Services.ScriptHandlerFactory, 
        System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
        PublicKeyToken=31BF3856AD364E35"/>
      <add verb="GET,HEAD" path="ScriptResource.axd" 
        type="System.Web.Handlers.ScriptResourceHandler, 
        System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
        PublicKeyToken=31BF3856AD364E35" validate="false"/>
    </httpHandlers>
    <httpModules>
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, 
        System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
        PublicKeyToken=31BF3856AD364E35"/>
    </httpModules>
    <sessionState mode="InProc" cookieless="AutoDetect" 
      timeout="20" sessionIDManagerType="
      Lanap.BotDetect.Persistence.CustomSessionIDManager, 
      Lanap.BotDetect"/>
    <customErrors mode="On" defaultRedirect="~/Error.html"/>
  </system.web>
  <system.web.extensions>
    <scripting>
      <webServices>
        <!-- Uncomment this line to customize maxJsonLength and add a 
          custom converter -->
        <!--
        <jsonSerialization maxJsonLength="500">
          <converters>
            <add name="ConvertMe" 
              type="Acme.SubAcme.ConvertMeTypeConverter"/>
          </converters>
        </jsonSerialization>
        -->
        <!-- Uncomment this line to enable the authentication service. 
          Include requireSSL="true" if appropriate. -->
        <!--
        <authenticationService enabled="true" 
          requireSSL = "true|false"/>
        -->
        <!-- Uncomment these lines to enable the profile service. 
          To allow profile properties to be retrieved and modified 
          in ASP.NET AJAX applications, you need to add each property 
          name to the readAccessProperties and writeAccessProperties 
          attributes. -->
        <!--
        <profileService enabled="true"
          readAccessProperties="propertyname1,propertyname2"
          writeAccessProperties="propertyname1,propertyname2" />
        -->
      </webServices>
      <!--
      <scriptResourceHandler enableCompression="true" 
        enableCaching="true" />
      -->
    </scripting>
  </system.web.extensions>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules>
      <remove name="ScriptModule"/><add name="ScriptModule" 
        preCondition="managedHandler" 
        type="System.Web.Handlers.ScriptModule, System.Web.Extensions, 
        Version=3.5.0.0, Culture=neutral, 
        PublicKeyToken=31BF3856AD364E35"/>
    </modules>
    <handlers>
      <remove name="ScriptHandlerFactory"/>
      <remove name="ScriptHandlerFactoryAppServices"/>
      <remove name="ScriptResource"/>
      <remove name="WebServiceHandlerFactory-Integrated"/>
      <add name="ScriptHandlerFactory" verb="*" path="*.asmx" 
        preCondition="integratedMode" type="System.Web.Script.
        Services.ScriptHandlerFactory, System.Web.Extensions, 
        Version=3.5.0.0, Culture=neutral, 
        PublicKeyToken=31BF3856AD364E35"/>
      <add name="ScriptHandlerFactoryAppServices" verb="*" 
        path="*_AppService.axd" preCondition="integratedMode" 
        type="System.Web.Script.Services.ScriptHandlerFactory, 
        System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
        PublicKeyToken=31BF3856AD364E35"/>
      <add name="ScriptResource" preCondition="integratedMode" 
        verb="GET,HEAD" path="ScriptResource.axd" 
        type="System.Web.Handlers.ScriptResourceHandler, 
        System.Web.Extensions, Version=3.5.0.0, Culture=neutral, 
         PublicKeyToken=31BF3856AD364E35"/>
      <remove name="LanapCaptchaHandler" />
      <add name="LanapCaptchaHandler" 
        preCondition="integratedMode" verb="*" 
        path="LanapCaptcha.aspx" 
        type="Lanap.BotDetect.CaptchaHandler, Lanap.BotDetect" />
    </handlers>
  </system.webServer>
  <system.codedom>
    <compilers>
      <compiler language="VB.NET;cs;csharp" extension=".cs" 
        type="Microsoft.CSharp.CSharpCodeProvider,System, 
        Version=2.0.0.0, Culture=neutral, 
        PublicKeyToken=b77a5c561934e089" warningLevel="4">
        <providerOption name="CompilerVersion" value="v3.5"/>
        <providerOption name="WarnAsError" value="false"/>
      </compiler>
      <compiler language="vb;vbs;visualbasic;vbscript" 
        extension=".vb" type="Microsoft.VisualBasic.VBCodeProvider, 
        System, Version=2.0.0.0, Culture=neutral, 
        PublicKeyToken=b77a5c561934e089" warningLevel="4">
        <providerOption name="CompilerVersion" value="v3.5"/>
        <providerOption name="OptionInfer" value="true"/>
        <providerOption name="WarnAsError" value="false"/>
      </compiler>
    </compilers>
  </system.codedom>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Extensions" 
          publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" 
          newVersion="3.5.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Extensions.Design" 
          publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" 
          newVersion="3.5.0.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Explanation

This version of the Web.config file is the one you will use with .NET Framework 3.5 and Visual Studio 2008. Lines necessary for BotDetect CAPTCHA to function properly have been bold, other lines are all standard values generated by Visual Studio 2008.

language: English Español Tiếng Việt