BotDetect ASP.NET MVC CAPTCHA C# Code Sample (BotDetect v2.0)
Please Note
The information on this page is out of date and applies to a deprecated version of BotDetect™ CAPTCHA (v2.0).
An up-to-date equivalent page for the latest BotDetect Captcha release (v3) is BotDetect v3 ASP.NET MVC CAPTCHA code sample.
General information about the major improvements in the current BotDetect release can be found at the What's New in BotDetect v3.0 page.
The BotDetect ASP.NET MVC code sample shows how to use BotDetect ASP.NET CAPTCHA protection in ASP.NET MVC applications. Starting from the standard ASP.NET MVC project created in Visual Studio (File > New Project > Visual C# > Web > ASP.NET MVC Web Application), we modify the Register.aspx page to include a CAPTCHA test before allowing users to register, ensuring only human users can create accounts.
Since the starting ASP.NET MVC project already contains a lot of content, we will not include all of it in this explanation, but only parts that need to be modified in order to apply BotDetect CAPTCHA protection to the Register page. Please note that this sample requires BotDetect ASP.NET CAPTCHA version 2.0.13 or higher.
Table of Contents
- Sample Project Location
- Views/Account/Register.aspx
- Attributes/CaptchaValidationAttribute.cs
- Controllers/AccountController.cs
- Views/Shared/Site.Master
- Views/Shared/HtmlHelper.cs
- Content/BotDetectLayout.css
- Content/BotDetectScripts.js
- Global.asax.cs
- Web.config
Sample Project Location
By default, this sample project is installed at
C:\Program Files\Lanapsoft\BotDetect\ASP.NET 2.0\v2.0\Samples\CSharpBotDetect2MvcDemo\.
You can also run it from the Start Menu:
Programs > Lanapsoft > BotDetect > ASP.NET 2.0 > v2.0 > Samples > C# BotDetect ASP.NET MVC CAPTCHA Sample.
Views/Account/Register.aspx
Full Source Code Listing
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="registerHead" ContentPlaceHolderID="head"
runat="server">
<title>Register</title>
</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>
<%= Html.ValidationSummary() %>
<% using (Html.BeginForm()) { %>
<div>
<fieldset>
<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>
<%
Lanap.BotDetect.MvcCaptcha registrationCaptcha =
new Lanap.BotDetect.MvcCaptcha("RegistrationCaptcha");
registrationCaptcha.TextStyle =
Lanap.BotDetect.TextStyleEnum.Lego;
registrationCaptcha.CodeLength = 4;
registrationCaptcha.ImageSize =
new System.Drawing.Size(245, 50);
registrationCaptcha.SaveProperties();
if (!registrationCaptcha.IsSolved)
{
%>
<%= Html.Captcha(registrationCaptcha) %>
<p>
<label for="captchaCode">Type the characters you see
in the picture:</label>
<%= Html.TextBox("captchaCode") %>
<%= Html.ValidationMessage("captchaCode")%>
</p>
<script type="text/javascript">
function LBD_ClearUserInput() {
var LBD_textBox = document.getElementById('captchaCode');
if(LBD_textBox) {
LBD_textBox.value = '';
}
}
LBD_RegisterHandler('PreReloadCaptchaImage',
LBD_ClearUserInput);
</script>
<%
}
%>
<p>
<input type="submit" value="Register" />
</p>
</fieldset>
</div>
<% } %>
</asp:Content>
Explanation
Instead of the regular Lanap.BotDetect.Captcha control used for ASP.NET Web Forms applications, we use a specialized Lanap.BotDetect.MvcCaptcha class, and set it's properties directly in the form code. Note that after property setting we have to call the SaveProperties method - otherwise these settings wouldn't be persisted.
After we have initialized the MvcCaptcha instance, we pass it as a parameter to a custom HtmlHelper used for MvcCaptcha rendering, but only if it hasn't already been successfully solved. In other words, once the user solves the Captcha, he is considered to have proven not to be a bot, and a new Captcha is not shown even if the validation of other fields (for example, the email address) fails.
Attributes/CaptchaValidationAttribute.cs
Source Code Listing
using System;
using System.Web.Mvc;
namespace Lanap.BotDetect.Attributes
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false,
Inherited = false)]
public sealed class CaptchaValidationAttribute : ActionFilterAttribute
{
public CaptchaValidationAttribute()
: this("captchaCode", "RegistrationCaptcha")
{
}
public CaptchaValidationAttribute(string inputfield,
string captchaId)
{
this.Field = inputfield;
this.CaptchaId = captchaId;
}
private string Field { get; set; }
private string CaptchaId { get; set; }
public override void OnActionExecuting(ActionExecutingContext
filterContext)
{
// make sure the captcha valid key is not contained in the
// route data
if (filterContext.RouteData.Values.ContainsKey("captchaValid"))
{
filterContext.RouteData.Values.Remove("captchaValid");
}
if (string.IsNullOrEmpty(this.CaptchaId))
{
filterContext.RouteData.Values.Add("captchaValid", false);
return;
}
string captchaCode =
filterContext.HttpContext.Request.Form[this.Field];
// Captcha validation
MvcCaptcha captchaInstance = new MvcCaptcha(this.CaptchaId);
string captchaInstanceId =
filterContext.HttpContext.Request.Form[
captchaInstance.CaptchaIdKey];
// the Captcha is only validated if it was included on the page
if (!(String.IsNullOrEmpty(captchaInstanceId)))
{
if ((captchaInstance.Validate(captchaCode, captchaInstanceId)))
{
filterContext.RouteData.Values.Add("captchaValid", true);
return;
}
}
filterContext.RouteData.Values.Add("captchaValid", false);
return;
}
}
}
Explanation
To validate the CAPTCHA user input, we create a new MvcCaptcha instance with the same name as added to the Register.aspx page ("RegistrationCaptcha"), and can validate the user input.
By checking for the presence of the captchaInstanceId hidden field, we can detect whether the Captcha was present on the page when it was submitted. This allows us to only validate the Captcha if the user hasn't already solved it.
The name used for each Captcha in the application allows us to have multiple different Captchas and validate them separately - for example, we could have a PostComment.aspx View page tied to the PostComment action in another controller, and we would then use a different Captcha name ("CommentCaptcha") to distinguish between them.
Controllers/AccountController.cs
Source Code Listing
Since this source code file contains a lot of pre-generated source, we are just showing the part that needs to be modified to include BotDetect CAPTCHA protection in the Register action.
[AcceptVerbs(HttpVerbs.Post)]
[CaptchaValidation("captchaCode", "RegistrationCaptcha")]
public ActionResult Register(string userName, string email,
string password, string confirmPassword, string captchaCode)
{
ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
if (ValidateRegistration(userName, email, password, confirmPassword,
captchaCode))
{
// Attempt to register the user
MembershipCreateStatus createStatus =
MembershipService.CreateUser(userName, password, email);
if (createStatus == MembershipCreateStatus.Success)
{
FormsAuth.SignIn(userName, false /* createPersistentCookie */);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("_FORM",
ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
return View();
}
private bool ValidateRegistration(string userName, string email,
string password, string confirmPassword, string captchaCode)
{
if (String.IsNullOrEmpty(userName))
{
ModelState.AddModelError("username",
"You must specify a username.");
}
if (String.IsNullOrEmpty(email))
{
ModelState.AddModelError("email",
"You must specify an email address.");
}
if (password == null ||
password.Length < MembershipService.MinPasswordLength)
{
ModelState.AddModelError("password",
String.Format(CultureInfo.CurrentCulture,
"You must specify a password of {0} or more characters.",
MembershipService.MinPasswordLength));
}
if (!String.Equals(password, confirmPassword,
StringComparison.Ordinal))
{
ModelState.AddModelError("_FORM",
"The new password and confirmation password do not match.");
}
// Captcha validation
if (!(bool)this.RouteData.Values["captchaValid"])
{
ModelState.AddModelError("captchaCode",
"The CAPTCHA code was incorrect!");
}
return ModelState.IsValid;
}
Explanation
Since we added a new TextBox for user CAPTCHA input, we must modify the Register and ValidateRegistration methods to accept an additional string parameter - captchaCode. In the ValidateRegistration method, we add a CAPTCHA validation check.
Views/Shared/Site.Master
Full Source Code Listing
<%@ Master Language="C#" 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">
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1" />
<asp:ContentPlaceHolder ID="head" runat="server">
<title></title>
</asp:ContentPlaceHolder>
<asp:PlaceHolder runat="server" id="includes">
<link href="<%= VirtualPathUtility.ToAbsolute(
"~/Content/Site.css") %>" rel="stylesheet" type="text/css" />
<link href="<%= VirtualPathUtility.ToAbsolute(
"~/Content/BotDetectLayout.css") %>" rel="stylesheet"
type="text/css" />
<script type='text/javascript' src='<%= VirtualPathUtility.
ToAbsolute("~/Content/BotDetectScripts.js") %>'></script>
</asp:PlaceHolder>
</head>
<body>
<div class="page">
<div id="header">
<div id="title">
<h1>My MVC Application</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>
Explanation
The only modification we make on the Master page is including the BotDetect client-side scripts and CSS declarations, which have to be copied to the Content folder. All includes are modified to use absolute paths (so pages in any level of the site hierarchy can use them), and placed withing a PlaceHolder to avoid a header bug present in ASP.NET MVC.
Views/Shared/HtmlHelper.cs
Full Source Code Listing
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Text;
namespace System.Web.Mvc
{
public static class CaptchaHtmlHelper
{
public static string Captcha(this HtmlHelper helper,
object captchaInstance)
{
Lanap.BotDetect.MvcCaptcha captcha =
captchaInstance as Lanap.BotDetect.MvcCaptcha;
StringBuilder markupBuilder = new StringBuilder();
markupBuilder.Append(@"<div class='LBD_CaptchaDiv' style='width:");
markupBuilder.Append(captcha.ImageSize.Width + 28);
markupBuilder.Append(@"px; height: ");
markupBuilder.Append(captcha.ImageSize.Height + 10);
markupBuilder.Append(@"px;'>
<div class='LBD_CaptchaImage' style='width:");
markupBuilder.Append(captcha.ImageSize.Width);
markupBuilder.Append(@"px; height: ");
markupBuilder.Append(captcha.ImageSize.Height);
markupBuilder.Append(@"px; '>
<img id='");
markupBuilder.Append(captcha.CaptchaId);
markupBuilder.Append(@"_CaptchaImage' src='");
markupBuilder.Append(captcha.ImageLink);
markupBuilder.Append(@"' alt='CAPTCHA Code Image' />
</div>
<div class='LBD_CaptchaIcons'>
<a href="");
markupBuilder.Append(captcha.SoundLink);
markupBuilder.Append("' onclick='LBD_LoadSound(\"");
markupBuilder.Append(captcha.CaptchaId);
markupBuilder.Append("_SoundPlaceholder\", \"");
markupBuilder.Append(captcha.SoundLink);
markupBuilder.AppendFormat("\");this.blur();return false;'>
<img src='{0}' alt='Play Sound' /></a>",
VirtualPathUtility.ToAbsolute("~/Content/Speaker.gif"));
markupBuilder.Append("<a href="#" onclick='LBD_ReloadImage(\"");
markupBuilder.Append(captcha.CaptchaId);
markupBuilder.AppendFormat("_CaptchaImage\");this.blur();
return false;'><img src='{0}' alt='Change the code' />
</a>", VirtualPathUtility.ToAbsolute("~/Content/Refresh.gif"));
markupBuilder.Append("<div id='");
markupBuilder.Append(captcha.CaptchaId);
markupBuilder.Append(@"_SoundPlaceholder'
class='LBD_placeholder'> </div>
</div>
</div>
<input type='hidden'
id='");
markupBuilder.Append(captcha.CaptchaIdKey);
markupBuilder.Append(@"'
name='");
markupBuilder.Append(captcha.CaptchaIdKey);
markupBuilder.Append(@"'
value='");
markupBuilder.Append(captcha.CurrentInstanceId);
markupBuilder.Append(@"' />");
return markupBuilder.ToString();
}
}
}
Explanation
In this file, we use an extension method to allow simple MvcCaptcha rendering from all ASP.NET MVC forms. Note that the speaker and reload icons are loaded from the application's Content folder.
Content/BotDetectLayout.css
Full Source Code Listing
.LBD_CaptchaDiv {
padding: 0 !important;
margin: 20px 0 0 10px;
overflow: visible !important;
}
*html .LBD_CaptchaDiv {
margin-bottom: -3px !important;
overflow: hidden !important;
}
.LBD_CaptchaDiv .LBD_CaptchaImage
{
float: left !important;
margin: 0 !important;
padding: 0 !important;
}
.LBD_CaptchaDiv .LBD_CaptchaIcons
{
width: 22px !important;
float: right !important;
text-align: left !important;
margin: 0 !important;
padding: 0 !important;
margin-bottom: -4px !important;
margin-top: -1px !important;
margin-right: 2px !important;
}
*html .LBD_CaptchaDiv .LBD_CaptchaIcons
{
margin-right: 1px !important;
}
.LBD_CaptchaDiv .LBD_CaptchaIcons a
{
margin: 0 !important;
padding: 0 !important;
display: block !important;
background-color: transparent !important;
text-decoration: none !important;
border: none !important;
}
.LBD_CaptchaDiv .LBD_CaptchaIcons a:focus,
.LBD_CaptchaDiv .LBD_CaptchaIcons a:active
{
border: none !important;
-moz-outline:none !important;
}
.LBD_CaptchaDiv .LBD_CaptchaIcons a img
{
border: 0 !important;
margin: 0 !important;
padding: 0 !important;
margin-top: 2px !important;
margin-bottom: 3px !important;
display: block !important;
}
.LBD_CaptchaDiv .LBD_CaptchaIcons a:focus img,
.LBD_CaptchaDiv .LBD_CaptchaIcons a:active img
{
border: 1px dotted #333 !important;
margin: 0 !important;
padding: 0 !important;
margin-top: 1px !important;
margin-bottom: 1px !important;
display: block !important;
}
*html .LBD_CaptchaDiv .LBD_CaptchaIcons a:focus img,
*html .LBD_CaptchaDiv .LBD_CaptchaIcons a:active img
{
border: 1px solid #999 !important;
margin-bottom: 3px !important;
}
*:first-child+html .LBD_CaptchaDiv .LBD_CaptchaIcons a:focus img,
*:first-child+html .LBD_CaptchaDiv .LBD_CaptchaIcons a:active img
{
border: 1px solid #999 !important;
}
.LBD_CaptchaDiv .LBD_CaptchaIcons .LBD_placeholder
{
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
}
*html .LBD_CaptchaDiv .LBD_CaptchaIcons .LBD_placeholder
{
display: none !important;
}
*:first-child+html .LBD_CaptchaDiv .LBD_CaptchaIcons .LBD_placeholder
{
display: none !important;
}
Explanation
In Web Forms ASP.NET applications, the CSS declarations used by the BotDetect Captcha control are embedded in the Lanap.BotDetect.dll assembly and included as Web Resources. Since this approach is not available in ASP.NET MVC applications, the same CSS declarations are here included as a plain .css file.
Content/BotDetectScripts.js
Full Source Code Listing
var LBD_ImgId = null;
var LBD_Img = null;
var LBD_NewImg = null;
var LBD_Parent = null;
var LBD_Prompt = null;
var LBD_Timer = null;
var LBD_TimerTicks = 0;
function LBD_LoadSound(soundPlaceholderId, soundLink)
{
if(document.getElementById)
{
var i = soundLink.indexOf('&d=');
if (-1 != i) {
soundLink = soundLink.substring(0, i);
}
soundLink = soundLink + '&d=' + LBD_GetTimestamp();
if ((-1 == soundLink.indexOf('&e=')) &&
(document.location.protocol == "https:")) {
soundLink = soundLink + '&e=1';
}
var placeholder = document.getElementById(soundPlaceholderId);
var objectSrc = "<object id='captchaSound'
classid='clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95'
height='0' width='0' style='width:0; height:0;'>
<param name='AutoStart' value='1' />
<param name='Volume' value='0' />
<param name='PlayCount' value='1' />
<param name='FileName' value='" + soundLink + "' />
<embed id='captchaSoundEmbed' src='"+ soundLink +
"' autoplay='true' hidden='true' volume='100'
type='"+ LBD_GetMimeType() +"' style='display:inline;' />
</object>";
placeholder.innerHTML = "";
placeholder.innerHTML = objectSrc;
}
}
function LBD_GetTimestamp() {
var d = new Date();
var t = d.getTime() + (d.getTimezoneOffset() * 60000);
return t;
}
function LBD_GetMimeType()
{
var mimeType = "audio/x-wav";
return mimeType;
}
function LBD_ReloadImage(imgId)
{
if(imgId)
{
LBD_ImgId = imgId;
LBD_Img = document.getElementById(LBD_ImgId);
var src = LBD_Img.src;
var i = src.indexOf('&d=');
if (-1 != i) {
src = src.substring(0, i);
}
var newSrc = src + '&d=' + LBD_GetTimestamp();
LBD_NewImg = document.createElement('img');
LBD_NewImg.onload = LBD_ShowImage;
LBD_NewImg.id = LBD_Img.id;
LBD_NewImg.alt = LBD_Img.alt;
LBD_NewImg.src = newSrc;
LBD_Prompt = document.createElement('span');
LBD_Prompt.appendChild(document.createTextNode('.'));
LBD_PreReloadImage();
LBD_Parent = LBD_Img.parentNode;
LBD_Parent.removeChild(LBD_Img);
LBD_Parent.appendChild(LBD_Prompt);
LBD_ShowProgress()
}
}
function LBD_ShowProgress()
{
if((LBD_Prompt)&&(LBD_TimerTicks < 100))
{
LBD_TimerTicks = LBD_TimerTicks + 1;
if(0 == LBD_TimerTicks % 5)
{
LBD_Prompt.firstChild.nodeValue = '.';
}
else
{
LBD_Prompt.firstChild.nodeValue =
LBD_Prompt.firstChild.nodeValue + '.';
}
LBD_Timer = setTimeout("LBD_ShowProgress()", 250);
}
else
{
clearTimeout(LBD_Timer);
LBD_TimerTicks = 0;
}
}
function LBD_ShowImage()
{
if(LBD_NewImg && LBD_Parent && LBD_Prompt)
{
LBD_Parent.removeChild(LBD_Prompt);
LBD_Parent.appendChild(LBD_NewImg);
LBD_Prompt = null;
LBD_PostReloadImage();
}
}
function LBD_PreReloadImage() {}
function LBD_PostReloadImage() {}
function LBD_RegisterHandler(eventName, userHandler)
{
switch(eventName.toLowerCase())
{
case 'prereloadcaptchaimage':
var LBD_OldHandler = LBD_PreReloadImage;
LBD_PreReloadImage = function() {
LBD_OldHandler();
userHandler();
}
break;
case 'postreloadcaptchaimage':
var oldHandler = LBD_PostReloadImage;
LBD_PostReloadImage = function() {
LBD_OldHandler();
userHandler();
}
break;
}
}
if ((typeof(Sys) != "undefined") &&
(typeof(Sys.Application) != "undefined")) {
Sys.Application.notifyScriptLoaded();
}
Explanation
In Web Forms ASP.NET applications, the JavaScript client-side scripts used by the BotDetect Captcha control are embedded in the Lanap.BotDetect.dll assembly and included as Web Resources. Since this approach is not available in ASP.NET MVC applications, the same JavaScript functions are here included as a plain .js file.
Global.asax.cs
Full Source Code Listing
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace CSharpBotDetectMvcDemo
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Account", action = "Register", id = "" }
);
routes.MapRoute(
"Root",
"",
new { controller = "Account", action = "Register", id = "" }
);
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}
}
}
Explanation
In order to make the Register action the default one in the application (so the CAPTCHA is immediately visible upon starting the application), we change the route mapping in the RegisterRoutes method.
Web.config
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>
<appSettings>
<add key="LBD_RequestPath" value="LanapCaptcha.axd" />
</appSettings>
<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"/>
<add assembly="System.Xml.Linq, Version=3.5.0.0,
Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Data.Linq, Version=3.5.0.0,
Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</assemblies>
</compilation>
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" />
</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>
<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>
<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.Linq"/>
<add namespace="System.Collections.Generic"/>
</namespaces>
</pages>
<sessionState mode="InProc" cookieless="AutoDetect" timeout="20"
sessionIDManagerType="Lanap.BotDetect.Persistence.
CustomSessionIDManager, Lanap.BotDetect" />
<customErrors mode="On" defaultRedirect="~/Content/Error.html"/>
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="LanapCaptcha.axd"
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"/>
<add verb="*" path="*.mvc" validate="false"
type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31BF3856AD364E35"/>
</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" />
<remove name="LanapCaptchaHandler" />
<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" />
<add name="LanapCaptchaHandler" verb="*"
path="LanapCaptcha.axd" type="Lanap.BotDetect.CaptchaHandler,
Lanap.BotDetect" />
</handlers>
</system.webServer>
</configuration>
Explanation
The first element we need to add to the Web.config file is the LBD_RequestPath declaration in the <appSettings> section. This is used to configure the BotDetect CAPTCHA paths to use the .axd extension, since the default .aspx extension is re-routed and processed by the ASP.NET MVC runtime.
The next change is the <sessionState> declaration, which has to register a custom sessionIDManager, ensuring the audio CAPTCHA works properly for Google Chrome and IE 7.0 + Vista users.
The <customErrors> sections is simply used to display a page pointing to the ASP.NET MVC download page, since not having the ASP.NET MVC installed is the most common error which can break this sample project. If you have ASP.NET MVC installed on your system and you are still being redirected to the Error.html page, please comment out the <customErrors> section so you can see the error details.
Finally, we register a BotDetect HttpHandler used for CAPTCHA image and sound generation in both the <httpHandlers> and the <system.webServer>/<handlers> sections (ensuring the CAPTCHA works for both servers using IIS 7.0 and the earlier versions). We use the modified .axd path in the handler declarations, as explained above.
Please Note
The information on this page is out of date and applies to a deprecated version of BotDetect™ CAPTCHA (v2.0).
An up-to-date equivalent page for the latest BotDetect Captcha release (v3) is BotDetect v3 ASP.NET MVC CAPTCHA code sample.
General information about the major improvements in the current BotDetect release can be found at the What's New in BotDetect v3.0 page.
Current BotDetect Versions
- BotDetect ASP.NET CAPTCHA v3.0.92011–11–21
- BotDetect ASP Classic CAPTCHA v3.0.92011–11–21






