ASP.NET MVC 1.0 Application Template CAPTCHA VB.NET Code Example

The ASP.NET MVC 1.0 application template Captcha example project shows how to use the BotDetect CAPTCHA MvcCaptcha control in ASP.NET MVC 1.0 web applications.

First Time Here?

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

Starting with the default ASP.NET MVC 1.0 Visual Studio 2008 project template, the example includes all code required to add CAPTCHA validation to the Account controller Register action.

The example remembers when the CAPTCHA is successfully solved within a single registration, and doesn't display it again if there are errors with other form values (the username, for example).

You can get a new CAPTCHA using the Register action link in the top right corner of the page, and see the explanation in the Account controller code.

Download the BotDetect ASP.NET CAPTCHA Generator archive to run this example

→ ASP.NET MVC version:

→ .NET programming language:

  • C#
  • VB.NET

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-mvc1-web.security.membership/vbnet/ folder; and contains the following files:

Views\Account\Register.aspx

<%@ Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" 
Inherits="System.Web.Mvc.ViewPage" %>

<%@ Import Namespace="AspNetMvc10CaptchaExampleVBNet" %>
<%@ Import Namespace="BotDetect.Web.Mvc" %>
<asp:Content ID="registerTitle" ContentPlaceHolderID="TitleContent" 
runat="server">
  Register
</asp:Content>
<asp:Content ID="BotDetectStylesheets" ContentPlaceHolderID="includes" 
runat="server">
  <link href="<%= BotDetect.Web.CaptchaUrls.Absolute.LayoutStyleSheetUrl %>" 
  rel="stylesheet" type="text/css" />
</asp:Content>
<asp:Content ID="registerContent" ContentPlaceHolderID="MainContent" 
runat="server">
  <h2>
    Create a New Account</h2>
  <p>
    Use the form below to create a new account.
  </p>
  <p>
    Passwords are required to be a minimum of
    <%=Html.Encode(ViewData("PasswordLength"))%>
    characters in length.
  </p>
  <p>
    <%= Html.ValidationSummary("Account creation was unsuccessful. Please 
    correct the errors and try again.") %>
  </p>
  <% Using Html.BeginForm("Register", "Account")%>
  <div>
    <fieldset id="RegisterFields">
      <legend>Account Information</legend>
      <p>
        <label for="username">
          Username:</label>
        <%= Html.TextBox("username") %>
        <%= Html.ValidationMessage("username") %>
      </p>
      <p>
        <label for="email">
          Email:</label>
        <%= Html.TextBox("email") %>
        <%= Html.ValidationMessage("email") %>
      </p>
      <p>
        <label for="password">
          Password:</label>
        <%= Html.Password("password") %>
        <%= Html.ValidationMessage("password") %>
      </p>
      <p>
        <label for="confirmPassword">
          Confirm password:</label>
        <%= Html.Password("confirmPassword") %>
        <%= Html.ValidationMessage("confirmPassword") %>
      </p>
      <%Dim registrationCaptcha As MvcCaptcha = CaptchaHelper.GetRegistrationCaptcha()
                    
        If (Not registrationCaptcha.IsSolved) Then%>
      <%= Html.Captcha(registrationCaptcha) %>
      <p>
        <label for="captchaCode">
          Please retype the characters from the picture:</label>
        <%= Html.TextBox("captchaCode")%>
        <%= Html.ValidationMessage("captchaCode")%>
      </p>
      <% End If%>
      <p>
        <input type="submit" value="Register" />
      </p>
    </fieldset>
  </div>
  <% End Using%>
</asp:Content>

BotDetect stylesheets are included in the generated page Header using the includes content placeholder defined in the Master page.

To keep View code simple, we delegate MvcCaptcha instance creation to a helper class, and use it along with Model fields to generate the required markup using straightforward HtmlHelper calls.

Since we want to avoid re-displaying the Captcha challenge to users after they solve it, we only call the markup generation code if the IsSolved property is not set by a previous successful Captcha validation.

Views\Shared\Site.Master

<%@ Master Language="VB" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!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 runat="server">
  <title>
    <asp:ContentPlaceHolder ID="TitleContent" runat="server" />
  </title>
  <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
  <asp:ContentPlaceHolder ID="includes" runat="server">
  </asp:ContentPlaceHolder>
</head>
<body>
  <div class="page">
    <div id="header">
      <div id="title">
        <h1>
          BotDetect CAPTCHA ASP.NET MVC 1.0 Example</h1>
      </div>
      <div id="logindisplay">
        <% Html.RenderPartial("LogOnUserControl")%>
      </div>
      <div id="menucontainer">
        <ul id="menu">
          <li>
            <%= Html.ActionLink("Home", "Index", "Home")%></li>
          <li>
            <%=Html.ActionLink("About", "About", "Home")%></li>
        </ul>
      </div>
    </div>
    <div id="main">
      <asp:ContentPlaceHolder ID="MainContent" runat="server" />
      <div id="footer">
      </div>
    </div>
  </div>
</body>
</html>

To allow easy inclusion of BotDetect stylesheets into Views which require them, the includes content placeholder should be declared in the Master page header.

Controllers\AccountController.vb

Imports System.Globalization
Imports System.Security.Principal
Imports BotDetect.Web.Mvc

<HandleError()> _
Public Class AccountController
  Inherits System.Web.Mvc.Controller

  Private _formsAuth As IFormsAuthentication
  Private _service As IMembershipService

  ' This constructor is used by the MVC framework to instantiate the controller using
  ' the default forms authentication and membership providers.

  Sub New()
    Me.New(Nothing, Nothing)
  End Sub

  ' This constructor is not used by the MVC framework but is instead provided for ease
  ' of unit testing this type. See the comments at the end of this file for more
  ' information.

  Sub New(ByVal formsAuth As IFormsAuthentication, 
  ByVal service As IMembershipService)
    _formsAuth = If(formsAuth, New FormsAuthenticationService())
    _service = If(service, New AccountMembershipService())
  End Sub

  ReadOnly Property FormsAuth() As IFormsAuthentication
    Get
      Return _formsAuth
    End Get
  End Property

  ReadOnly Property MembershipService() As IMembershipService
    Get
      Return _service
    End Get
  End Property

  Function LogOn() As ActionResult

    ViewData("Title") = "Log On"

    Return View()
  End Function

  <AcceptVerbs(HttpVerbs.Post)> _
  <System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", 
  "CA1054: UriParametersShouldNotBeStrings", _
          Justification:="Needs to take same parameter type as Controller.Redirect()")> _
  Function LogOn(ByVal userName As String, ByVal password As String, 
  ByVal rememberMe As Boolean, ByVal returnUrl As String) As ActionResult

    ViewData("Title") = "Log On"

    If Not ValidateLogOn(userName, password) Then
      ViewData("rememberMe") = rememberMe
      Return View()
    End If

    FormsAuth.SignIn(userName, rememberMe)
    If Not String.IsNullOrEmpty(returnUrl) Then
      Return Redirect(returnUrl)
    Else
      Return RedirectToAction("Index", "Home")
    End If

  End Function

  Function LogOff() As ActionResult

    FormsAuth.SignOut()

    Return RedirectToAction("Index", "Home")
  End Function

  Function Register() As ActionResult

    ViewData("Title") = "Register"
    ViewData("PasswordLength") = MembershipService.MinPasswordLength

    ' when the View is accessed directly and not posted, we clear any
    ' remembered CAPTCHA solving state. 
    ' The users only have to solve the CAPTCHA once within a single 
    ' registration, but if they reload the Register page later,
    ' it is shown again. 
    ' Otherwise, they could register an unlimited number of accounts 
    ' within a single Session after solving the CAPTCHA only once.
    MvcCaptcha.ResetCaptcha("RegistrationCaptcha")

    Return View()
  End Function

  <AcceptVerbs(HttpVerbs.Post)> _
  <CaptchaValidationActionFilter("captchaCode", "RegistrationCaptcha", 
  "Your input doesn't match displayed characters.")> _
  Function Register(ByVal userName As String, ByVal email As String, 
  ByVal password As String, ByVal confirmPassword As String) As ActionResult

    ViewData("Title") = "Register"
    ViewData("PasswordLength") = MembershipService.MinPasswordLength

    If ValidateRegistration(userName, email, password, confirmPassword) Then
      ' Attempt to register the user
      Dim createStatus As MembershipCreateStatus = MembershipService.CreateUser(
      userName, password, email)

      If createStatus = MembershipCreateStatus.Success Then
        FormsAuth.SignIn(userName, False)
        Return RedirectToAction("Index", "Home")
      Else
        ModelState.AddModelError("_FORM", ErrorCodeToString(createStatus))
      End If
    End If

    Return View()
  End Function

  <Authorize()> _
  Function ChangePassword() As ActionResult

    ViewData("Title") = "Change Password"
    ViewData("PasswordLength") = MembershipService.MinPasswordLength

    Return View()
  End Function

  <Authorize()> _
  <AcceptVerbs(HttpVerbs.Post)> _
  <System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", 
  "CA1031:DoNotCatchGeneralExceptionTypes", _
          Justification:="Exceptions result in password not being changed.")> _
  Function ChangePassword(ByVal currentPassword As String, ByVal newPassword As String, 
    ByVal confirmPassword As String) As ActionResult

    ViewData("Title") = "Change Password"
    ViewData("PasswordLength") = MembershipService.MinPasswordLength

    If Not ValidateChangePassword(currentPassword, newPassword, confirmPassword) 
    Then
      Return View()
    End If

    Try
      If MembershipService.ChangePassword(User.Identity.Name, currentPassword, 
      newPassword) Then
        Return RedirectToAction("ChangePasswordSuccess")
      Else
        ModelState.AddModelError("_FORM", 
        "The current password is incorrect or the new password is invalid.")
        Return View()
      End If
    Catch ex As Exception
        ModelState.AddModelError("_FORM", 
        "The current password is incorrect or the new password is invalid.")
        Return View()
    End Try
  End Function

  Function ChangePasswordSuccess() As ActionResult

    ViewData("Title") = "Change Password"

    Return View()
  End Function

  Protected Overrides Sub OnActionExecuting(ByVal filterContext As System.Web.Mvc.ActionExecutingContext)
    If TypeOf filterContext.HttpContext.User.Identity Is WindowsIdentity Then
      Throw New InvalidOperationException("Windows authentication is not supported.")
    End If
  End Sub

#Region "Validation Methods"

  Private Function ValidateChangePassword(ByVal currentPassword As String, ByVal 
  newPassword As String, ByVal confirmPassword As String) As Boolean
    If String.IsNullOrEmpty(currentPassword) Then
      ModelState.AddModelError("currentPassword", "You must specify a current password.")
    End If

    If newPassword Is Nothing OrElse newPassword.Length < MembershipService.MinPasswordLength Then
      ModelState.AddModelError("newPassword", 
      String.Format(CultureInfo.CurrentCulture, 
      "You must specify a new password of {0} or more characters.", _
                                             MembershipService.MinPasswordLength) )
    End If

    If Not String.Equals(newPassword, confirmPassword, StringComparison.Ordinal) 
    Then
      ModelState.AddModelError("_FORM", 
      "The new password and confirmation password do not match.")
    End If

    Return ModelState.IsValid
  End Function

  Private Function ValidateLogOn(ByVal userName As String, 
  ByVal password As String) As Boolean
    If String.IsNullOrEmpty(userName) Then
      ModelState.AddModelError("username", "You must specify a username.")
    End If

    If String.IsNullOrEmpty(password) Then
      ModelState.AddModelError("password", "You must specify a password.")
    End If

    If Not MembershipService.ValidateUser(userName, password) Then
      ModelState.AddModelError("_FORM", 
      "The username or password provided is incorrect.")
    End If

    Return ModelState.IsValid
  End Function

  Private Function ValidateRegistration(ByVal userName As String, 
  ByVal email As String, ByVal password As String, ByVal confirmPassword As String) As Boolean
    If String.IsNullOrEmpty(userName) Then
      ModelState.AddModelError("username", "You must specify a username.")
    End If

    If String.IsNullOrEmpty(email) Then
      ModelState.AddModelError("email", "You must specify an email address.")
    End If

    If password Is Nothing OrElse password.Length < MembershipService.MinPasswordLength Then
      ModelState.AddModelError("password", 
      String.Format(CultureInfo.CurrentCulture, _
      "You must specify a password of {0} or more characters.", _
                                             MembershipService.MinPasswordLength))
    End If

    If Not String.Equals(password, confirmPassword, StringComparison.Ordinal) 
    Then
      ModelState.AddModelError("_FORM", 
      "The new password and confirmation password do not match.")
    End If

    Return ModelState.IsValid
  End Function

  Private Shared Function ErrorCodeToString(ByVal createStatus As MembershipCreateStatus) As String
    ' See http://msdn.microsoft.com/en-us/library/system.web.security.membershipcreatestatus.aspx for
    ' a full list of status codes.
    Select Case createStatus
      Case MembershipCreateStatus.DuplicateUserName
        Return "Username already exists. Please enter a different user name."

      Case MembershipCreateStatus.DuplicateEmail
        Return "A username for that e-mail address already exists. Please enter 
        a different e-mail address."

      Case MembershipCreateStatus.InvalidPassword
        Return "The password provided is invalid. Please enter a valid password 
        value."

      Case MembershipCreateStatus.InvalidEmail
        Return "The e-mail address provided is invalid. Please check the value 
        and try again."

      Case MembershipCreateStatus.InvalidAnswer
        Return "The password retrieval answer provided is invalid. Please check 
        the value and try again."

      Case MembershipCreateStatus.InvalidQuestion
        Return "The password retrieval question provided is invalid. Please 
        check the value and try again."

      Case MembershipCreateStatus.InvalidUserName
        Return "The user name provided is invalid. Please check the value and 
        try again."

      Case MembershipCreateStatus.ProviderError
        Return "The authentication provider returned an error. Please verify 
        your entry and try again. If the problem persists, please contact your 
        system administrator."

      Case MembershipCreateStatus.UserRejected
        Return "The user creation request has been canceled. Please verify your 
        entry and try again. If the problem persists, please contact your system 
        administrator."

      Case Else
        Return "An unknown error occurred. Please verify your entry and try 
        again. If the problem persists, please contact your system administrator.
        "
    End Select

  End Function
#End Region

End Class

' The FormsAuthentication type is sealed and contains static members, so it is 
' difficult to
' unit test code that calls its members. The interface and helper class below 
' demonstrate
' how to create an abstract wrapper around such a type in order to make the 
' AccountController
' code unit testable.

Public Interface IFormsAuthentication

  Sub SignIn(ByVal userName As String, ByVal createPersistentCookie As Boolean)
  Sub SignOut()

End Interface


Public Class FormsAuthenticationService
  Implements IFormsAuthentication

  Public Sub SignIn(ByVal userName As String, ByVal createPersistentCookie As 
  Boolean) Implements IFormsAuthentication.SignIn
    FormsAuthentication.SetAuthCookie(userName, createPersistentCookie)
  End Sub

  Public Sub SignOut() Implements IFormsAuthentication.SignOut
    FormsAuthentication.SignOut()
  End Sub

End Class

Public Interface IMembershipService
  ReadOnly Property MinPasswordLength() As Integer

  Function ChangePassword(ByVal userName As String, ByVal oldPassword As String, 
  ByVal newPassword As String) As Boolean
  Function CreateUser(ByVal userName As String, ByVal password As String, 
  ByVal email As String) As MembershipCreateStatus
  Function ValidateUser(ByVal userName As String, ByVal password As String) As 
  Boolean

End Interface

Public Class AccountMembershipService
  Implements IMembershipService

  Private _provider As MembershipProvider

  Sub New()
    Me.New(Nothing)
  End Sub

  Sub New(ByVal provider As MembershipProvider)
    _provider = If(provider, Membership.Provider)
  End Sub

  Public ReadOnly Property MinPasswordLength() As Integer Implements 
  IMembershipService.MinPasswordLength
    Get
      Return _provider.MinRequiredPasswordLength
    End Get
  End Property

  Function ChangePassword(ByVal userName As String, ByVal oldPassword As String, 
  ByVal newPassword As String) As Boolean Implements IMembershipService.ChangePassword
    Dim currentUser As MembershipUser = _provider.GetUser(userName, True)
    Return currentUser.ChangePassword(oldPassword, newPassword)
  End Function

  Function CreateUser(ByVal userName As String, ByVal password As String, 
  ByVal email As String) As MembershipCreateStatus Implements IMembershipService.CreateUser
    Dim status As MembershipCreateStatus
    _provider.CreateUser(userName, password, email, Nothing, Nothing, True, 
    Nothing, status)
    Return status
  End Function

  Function ValidateUser(ByVal userName As String, ByVal password As String) As 
  Boolean Implements IMembershipService.ValidateUser
    Return _provider.ValidateUser(userName, password)
  End Function

End Class

To add Captcha validation to the Register action Controller code, we perform a single line of setup in the Register action when the user GETs it, and execute the <CaptchaValidationActionFilter> filter when the user POSTs it.

The filter attribute will automatically add the appropriate ModelState error if the Captcha code input doesn't match the code displayed to the user in the Captcha picture.

CaptchaHelper.vb

Imports BotDetect
Imports BotDetect.Web
Imports BotDetect.Web.UI
Imports BotDetect.Web.Mvc

Public Class CaptchaHelper

  Public Shared Function GetRegistrationCaptcha() As MvcCaptcha

    ' create the control instance
    Dim registrationCaptcha As MvcCaptcha = _
        New MvcCaptcha("RegistrationCaptcha")

    registrationCaptcha.UserInputID = "captchaCode"

    ' Captcha properties are set in this event handler
    AddHandler WebFormsCaptcha.InitializedWebCaptcha, _
        AddressOf RegistrationCaptcha_InitializedWebCaptcha

    Return registrationCaptcha

  End Function

  ' event handler used for Captcha control property randomization
  Public Shared Sub RegistrationCaptcha_InitializedWebCaptcha( _
      ByVal sender As Object, _
      ByVal e As BotDetect.InitializedWebCaptchaEventArgs)

    If (e.CaptchaId <> "RegistrationCaptcha") Then
      Return
    End If

    Dim registrationCaptcha As Captcha = TryCast(sender, Captcha)

    ' fixed Captcha settings 
    registrationCaptcha.ImageSize = New System.Drawing.Size(200, 50)
    registrationCaptcha.CodeLength = 4

    ' randomized Captcha settings
    registrationCaptcha.ImageStyle = CaptchaRandomization.GetRandomImageStyle()
    registrationCaptcha.SoundStyle = CaptchaRandomization.GetRandomSoundStyle()
  End Sub

End Class

Captcha instance creation and property setting is encapsulated in this simple helper class. This separation allows application Views to stay simple regardless of the amount of Captcha customization chosen.

Global.asax.vb

' Note: For instructions on enabling IIS6 or IIS7 classic mode, 
' visit http://go.microsoft.com/?LinkId=9394802

Public Class MvcApplication
  Inherits System.Web.HttpApplication

  Public Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

    ' BotDetect requests must not be routed
    routes.IgnoreRoute("{*botdetect}", 
    New With {.botdetect = "(.*) BotDetectCaptcha\.ashx"})


    ' Set the Register action as the example project default, 
    ' since it includes the Captcha control and we want to show it
    routes.MapRoute( _
        "Default", _
        "{controller}/{action}/{id}", _
        New With {.controller = "Account", .action = "Register", .id = ""} _
    )
  End Sub

  Sub Application_Start()
    RegisterRoutes(RouteTable.Routes)
  End Sub
End Class

Since all BotDetect requests are handled by the BotDetect HttpHandler, ASP.NET Url Routing must be configured to ignore BotDetect requests, which can be achieved by a single line of code in Global.asax code-behind.

Web.config

<?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>
    <!-- Register the BotDetect configuration section -->
    <section name="botDetect" requirePermission="false" 
    type="BotDetect.Configuration.BotDetectConfigurationSection, BotDetect"/>
  </configSections>
  <connectionStrings>
    <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;
    Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User 
    Instance=true" providerName="System.Data.SqlClient"/>
  </connectionStrings>
  <system.web>
    <compilation debug="false">
      <assemblies>
        <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.Web.Abstractions, Version=3.5.0.0, Culture=neutral,
        PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, 
        PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, 
        PublicKeyToken=31BF3856AD364E35"/>
        <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, 
        Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
      </assemblies>
    </compilation>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880" />
    </authentication>
    <membership>
      <providers>
        <clear/>
        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.
        SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, 
        PublicKeyToken=b03f5f7f11d50a3a" 
        connectionStringName="ApplicationServices" 
        enablePasswordRetrieval="false" enablePasswordReset="true" 
        requiresQuestionAndAnswer="false" requiresUniqueEmail="false" 
        passwordFormat="Hashed" maxInvalidPasswordAttempts="5" 
        minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" 
        passwordAttemptWindow="10" passwordStrengthRegularExpression="" 
        applicationName="/"/>
      </providers>
    </membership>
    <profile>
      <providers>
        <clear/>
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.
        SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, 
        PublicKeyToken=b03f5f7f11d50a3a" 
        connectionStringName="ApplicationServices" applicationName="/"/>
      </providers>
    </profile>
    <roleManager enabled="false">
      <providers>
        <clear/>
        <add connectionStringName="ApplicationServices" applicationName="/" 
        name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, 
        System.Web, Version=2.0.0.0, Culture=neutral, 
        PublicKeyToken=b03f5f7f11d50a3a"/>
        <add applicationName="/" name="AspNetWindowsTokenRoleProvider" 
        type="System.Web.Security.WindowsTokenRoleProvider, System.Web, 
        Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
      </providers>
    </roleManager>
    <!-- make sure Session State is enabled -->
    <pages enableSessionState="true">
      <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>
      <namespaces>
        <add namespace="System.Web.Mvc"/>
        <add namespace="System.Web.Mvc.Ajax"/>
        <add namespace="System.Web.Mvc.Html"/>
        <add namespace="System.Web.Routing"/>
        <add namespace="System.Collections.Generic"/>
        <!-- add BotDetect namespaces for coding convenience -->
        <add namespace="BotDetect"/>
        <add namespace="BotDetect.Web"/>
        <add namespace="BotDetect.Web.UI"/>
        <add namespace="BotDetect.Web.Mvc"/>
      </namespaces>
    </pages>
    <!-- configure Session State for BotDetect use -->
    <sessionState mode="InProc" cookieless="AutoDetect" timeout="20" 
    sessionIDManagerType="BotDetect.Web.CustomSessionIdManager, BotDetect"/>
    <httpHandlers>
      <remove verb="*" path="*.asmx"/>
      <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"/>
      <add verb="*" path="*.mvc" validate="false" type="System.Web.Mvc.
      MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, 
      PublicKeyToken=31BF3856AD364E35"/>
      <!-- register HttpHandler used for BotDetect Captcha requests -->
      <add verb="GET" path="BotDetectCaptcha.ashx" 
      type="BotDetect.Web.CaptchaHandler, BotDetect"/>
    </httpHandlers>
    <httpModules>
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.
      Web.Extensions, Version=3.5.0.0, Culture=neutral, 
      PublicKeyToken=31BF3856AD364E35"/>
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, 
      System.Web.Routing, Version=3.5.0.0, Culture=neutral, 
      PublicKeyToken=31BF3856AD364E35"/>
    </httpModules>
  </system.web>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" 
      type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, 
      Culture=neutral, PublicKeyToken=b77a5c561934e089">
        <providerOption name="CompilerVersion" value="v3.5"/>
        <providerOption name="WarnAsError" value="false"/>
      </compiler>
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" 
      warningLevel="4" type="Microsoft.VisualBasic.VBCodeProvider, System, 
      Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
        <providerOption name="CompilerVersion" value="v3.5"/>
        <providerOption name="OptionInfer" value="true"/>
        <providerOption name="WarnAsError" value="false"/>
      </compiler>
    </compilers>
  </system.codedom>
  <system.web.extensions/>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="ScriptModule"/>
      <remove name="UrlRoutingModule"/>
      <add name="ScriptModule" preCondition="managedHandler" type="System.Web.
      Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, 
      Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, 
      System.Web.Routing, Version=3.5.0.0, Culture=neutral, 
      PublicKeyToken=31BF3856AD364E35"/>
    </modules>
    <handlers>
      <remove name="WebServiceHandlerFactory-Integrated"/>
      <remove name="ScriptHandlerFactory"/>
      <remove name="ScriptHandlerFactoryAppServices"/>
      <remove name="ScriptResource"/>
      <remove name="MvcHttpHandler"/>
      <remove name="UrlRoutingHandler"/>
      <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"/>
      <add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.
      mvc" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, 
      Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" 
      path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, 
      Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
      <!-- register HttpHandler used for BotDetect Captcha requests -->
      <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>

The application's web.config file includes the standard BotDetect HttpHandler and Session state configuration elements.