ASP.NET CAPTCHA Request Dynamic Settings VB.NET Code Example

The ASP.NET Captcha request dynamic settings example project shows how to dynamically adjust BotDetect CAPTCHA configuration, potentially on each Http request made by the client.

First Time Here?

Check the BotDetect Developer Crash Course for key integration steps.

Any code setting Captcha properties in the Captcha.InitializedWebCaptcha event handler will be executed not only for each protected form GET or POST request (like Captcha configuration code placed in form source would be), but also for each each GET request loading a Captcha image or sound, or making an Ajax Captcha validation call.

If configured values are dynamic (e.g. randomized from a range), they will be re-calculated for each Captcha challenge generated. For example, Captcha ImageStyle randomized in Captcha.InitializedWebCaptcha event handler code will change on each Captcha reload button click.

This means your code can reliably keep track of visitor interaction with the Captcha challenge and dynamically adjust its settings. Also, while Captcha.InitializedWebCaptcha settings apply to all Captcha instances by default, you can also selectively apply them based on CaptchaId.

To show an example of the possible dynamic Captcha configuration adjustments, this code example increases the difficulty of the Captcha test if the visitor associated with the current ASP.NET Session fails a certain number of Captcha validation attempts, and also sets the Captcha locale to Chinese for requests from a certain IP range.

Download the BotDetect ASP.NET CAPTCHA Generator archive to run this example
  • C#
  • VB.NET

Visual Studio 2005-2017 / .NET 2.0 and onwards

Within this page, the root folder of the extracted archive is referred as the <BDC-DIR>.

This example is in the <BDC-DIR>/lgcy-on-lgcy/examples/t_api-captcha~conf_via-dynamic_config/vbnet/ folder; and contains the following files:

Default.aspx

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

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>BotDetect ASP.NET CAPTCHA Options: Request Dynamic Settings Code 
  Example</title>
  <link type="text/css" rel="Stylesheet" href="StyleSheet.css" />
</head>
<body>
  <form runat="server" class="column" id="form1">
    <h1>BotDetect ASP.NET CAPTCHA Options:
            <br />
      Request Dynamic Settings Code Example</h1>

    <fieldset>
      <legend>ASP.NET WebForm CAPTCHA Validation</legend>
      <p class="prompt">
        <label for="CaptchaCodeTextBox">Retype the characters from the picture:</label>
      </p>
      <BotDetect:WebFormsCaptcha runat="server" ID="DynamicCaptcha" 
      UserInputID="CaptchaCodeTextBox" />
      <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>

    <div id="output">
      <asp:Literal runat="server" ID="StatusLiteral" />
    </div>
  </form>
</body>
</html>

Default.aspx.vb

Imports BotDetect.Web
Imports BotDetect
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Partial Class _Default Inherits System.Web.UI.Page

  Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) 
  Handles Me.Init
    AddHandler Captcha.InitializedWebCaptcha, AddressOf 
    DynamicCaptcha_InitializedWebCaptcha

  End Sub

  Private Sub DynamicCaptcha_InitializedWebCaptcha(ByVal sender As Object, 
  ByVal e As InitializedWebCaptchaEventArgs) Handles DynamicCaptcha.InitializedWebCaptcha

    Dim captchaInstance As Captcha
    captchaInstance = DirectCast(sender, Captcha)

    ' Captcha.InitializedWebCaptcha event handlers are global and apply to all 
    ' Captcha instances 
    ' in the application if some settings need to be apply only to a particular 
    ' Captcha 
    ' instance, this is how settings can be conditionally applied based on 
    ' CaptchaId
    If (e.CaptchaId = DynamicCaptcha.CaptchaId) Then

      captchaInstance.SoundEnabled = False
    End If

    ' re-calculated on each image request
    Dim imageStyles As ImageStyle() = {ImageStyle.Graffiti, ImageStyle.SunAndWarmAir, ImageStyle.Overlap}
    captchaInstance.ImageStyle = CaptchaRandomization.GetRandomImageStyle(imageStyles)

    ' dynamic Captcha settings depending on failed validation attempts: increase 
    ' Captcha 
    ' difficulty according to number of previously failed validations
    Dim count As Integer = DynamicCaptchaExample.ValidationCounter.GetFailedValidationsCount()
    If (count < 3) Then

      captchaInstance.CodeLength = CaptchaRandomization.GetRandomCodeLength(3, 4)
      captchaInstance.CodeStyle = CodeStyle.Numeric
      captchaInstance.CodeTimeout = 600 ' 10 minutes

    ElseIf (count < 10) Then

      captchaInstance.CodeLength = CaptchaRandomization.GetRandomCodeLength(4, 6)
      captchaInstance.CodeStyle = CodeStyle.Alpha
      captchaInstance.CodeTimeout = 180 ' 3 minutes

    Else

      captchaInstance.CodeLength = CaptchaRandomization.GetRandomCodeLength(6, 9)
      captchaInstance.CodeStyle = CodeStyle.Alphanumeric
      captchaInstance.CodeTimeout = 60 ' 1 minute
    End If

    ' set Captcha locale to Chinese for requests from a certain IP range
    Dim ipRange As String = "223.254."
    Dim requestFromRangeDetected As Boolean = False

    ' have to use HttpContext.Current.Request and not Page.Request because Page
    ' properties won't be set for Captcha image and sound requests serverd directly
    ' by the BotDetect Captcha HttpHandler
    If (Not (HttpContext.Current.Request Is Nothing) And
      Not String.IsNullOrEmpty(HttpContext.Current.Request.UserHostAddress)
      And HttpContext.Current.Request.UserHostAddress.StartsWith(ipRange)) 
    Then

      requestFromRangeDetected = True
    End If

    If (requestFromRangeDetected) Then

      captchaInstance.CodeStyle = CodeStyle.Alpha
      captchaInstance.Locale = "cmn"
    End If
  End Sub

  Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As  _
  System.EventArgs) Handles Me.PreRender
    ' initial page setup
    If (Not IsPostBack) Then

      ' set control text
      ValidateCaptchaButton.Text = "Validate"
      CaptchaCorrectLabel.Text = "Correct!"
      CaptchaIncorrectLabel.Text = "Incorrect!"

      ' these messages are shown only after validation
      CaptchaCorrectLabel.Visible = False
      CaptchaIncorrectLabel.Visible = False
    End If

    If (IsPostBack) Then

      ' validate the Captcha to check we're not dealing with a bot
      Dim isHuman As Boolean = DynamicCaptcha.Validate()
      If (isHuman) Then

        CaptchaCorrectLabel.Visible = True
        CaptchaIncorrectLabel.Visible = False
        DynamicCaptchaExample.ValidationCounter.ResetFailedValidationsCount()

      Else

        CaptchaCorrectLabel.Visible = False
        CaptchaIncorrectLabel.Visible = True
        DynamicCaptchaExample.ValidationCounter.IncrementFailedValidationsCount()
      End If
    End If

    ' update status display
    Dim count As Integer = DynamicCaptchaExample.ValidationCounter.GetFailedValidationsCount()
    StatusLiteral.Text = String.Format("<p>Failed Captcha validations: {0}</p>", 
    count)
    If (count < 3) Then

      StatusLiteral.Text += "<p>Dynamic Captcha difficulty: Easy</p>"

    ElseIf (count < 10) Then

      StatusLiteral.Text += "<p>Dynamic Captcha difficulty: Moderate</p>"

    Else

      StatusLiteral.Text += "<p>Dynamic Captcha difficulty: Hard</p>"
    End If
  End Sub
End Class

App_Code\Counter.vb

Imports Microsoft.VisualBasic
Imports System
Namespace DynamicCaptchaExample
  ' <summary>
  ' Summary description for Counter
  ' </summary>
  Public Class ValidationCounter

    Const FailedValidationsCountKey As String = "FailedValidationsCountKey"

    Public Shared Function GetFailedValidationsCount() As Integer

      Dim count As Integer = 0
      Dim saved As Object = HttpContext.Current.Session(FailedValidationsCountKey)
      If (Not (saved Is Nothing)) Then

        Try

          count = DirectCast(saved, Integer)

        Catch ex As InvalidCastException

          ' ignore cast errors
          count = 0
        End Try
      End If
      Return count

    End Function
    Public Shared Sub IncrementFailedValidationsCount()

      Dim count As Integer = GetFailedValidationsCount()
      count += 1
      HttpContext.Current.Session(FailedValidationsCountKey) = count
    End Sub

    Public Shared Sub ResetFailedValidationsCount()

      HttpContext.Current.Session.Remove(FailedValidationsCountKey)
    End Sub
  End Class
End Namespace

Web.config

<?xml version="1.0"?>

<!--
  For more information on how to configure your ASP.NET application, please 
  visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->

<configuration>
  <configSections>
    <section name="botDetect" requirePermission="false" 
    type="BotDetect.Configuration.BotDetectConfigurationSection, BotDetect"/>
  </configSections>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
    <add key="ValidationSettings:UnobtrusiveValidationMode" value="None"/>
  </appSettings>
  <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 controlRenderingCompatibilityVersion="4.5" 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="false" targetFramework="4.5"/>
    <httpRuntime requestValidationMode="4.5" targetFramework="4.5" 
    encoderType="System.Web.Security.AntiXss.AntiXssEncoder, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
    <machineKey compatibilityMode="Framework45"/>
  </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>
  <botDetect helpLinkEnabled="true" helpLinkMode="image" />
</configuration>