BotDetect ASP.NET 2.0 Ajax CAPTCHA C# Code Sample
The ASP.NET Ajax CAPTCHA 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, regardless 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).
Sample Project Location
By default, this sample project is installed at
C:\Program Files\Lanapsoft\BotDetect\ASP.NET 2.0\v2.0\Samples\CSharpBotDetect2MSAjaxDemo\.
You can also run it from the Start Menu:
Programs > Lanapsoft > BotDetect > ASP.NET 2.0 > v2.0 > Samples > C# BotDetect MS Ajax Demo Preview.
Default.aspx
Full Source Code Listing
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" 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 bolded. 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.cs
Full Source Code Listing
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
/// initial page setup
if (!IsPostBack)
{
/// 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;
}
CodeTextBox.Attributes.Add("onkeyup",
"this.value = this.value.toLowerCase();");
if (IsPostBack)
{
/// validate the input code, and show the
/// appropriate message
string code = CodeTextBox.Text.Trim().ToUpper();
if (SampleCaptcha.Validate(code))
{
MessageCorrectLabel.Visible = true;
MessageIncorrectLabel.Visible = false;
}
else
{
MessageCorrectLabel.Visible = false;
MessageIncorrectLabel.Visible = true;
}
/// clear previous user code input
CodeTextBox.Text = null;
}
}
}
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 lifecycle), except that changes to controls outside the <ContentTemplate> are effectively discarded.
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=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. If you are using .NET Framework 3.5 and Visual Studio 2008, you should replace this file with the next one (Web_3.5.config). Lines neccesary for BotDetect CAPTCHA to function properly have been bolded, other lines are all standard values generated by Visual Studio 2005 with ASP.NET Ajax Extensions 1.0 installed.
Web_3.5.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>
<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="c#;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, so if that applies to you, you should rename it to Web.config and overwrite the existing file. If you are using .NET Framework 2.0 + ASP.NET Ajax Extensions 1.0, you should use the default version. Lines neccesary for BotDetect CAPTCHA to function properly have been bolded, other lines are all standard values generated by Visual Studio 2008.
Error.html
Full Source Code Listing
<!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 id="Head1" runat="server">
<title>Untitled Page</title>
<link type='text/css' rel='Stylesheet' href='StyleSheet.css' />
</head>
<body>
<form id="form1" runat="server">
<div style="font-size: 0.9em;">
<p style="margin-left:11pt;">
An error occured while trying to run the sample.
</p>
<fieldset>
<legend>.NET 2.0 / .NET 3.0 / Visual Studio 2005 Users
</legend>
<p>
Do you have ASP.NET Ajax Extensions installed? If not,
you can get them from <a href="http://www.microsoft.com/
downloads/details.aspx?FamilyID=ca9d90fa-e8c9-42e3-aa19-
08e2c027f5d6&displaylang=en" title="ASP.NET Ajax
Exstensions download">Microsoft's download site</a>.
</p>
</fieldset>
<fieldset>
<legend>.NET 3.5 / Visual Studio 2008 Users</legend>
<p>
Rename the "Web_3.5.config" file in the sample folder to
"Web.config", or open the sample project in Visual Studio
2008 and run the Conversion Wizard.
</p>
</fieldset>
</div>
</form>
</body>
</html>
Explanation
The most commmon source of errors when running the ASP.NET Ajax CAPTCHA sample is not having the ASP.NET Ajax Extensions installed, and this file is used as the default error page to provide instuctions about installing them.
Also, since the .NET 3.5 / Visual Studio 2008 ASP.NET applications need to use different Web.config settings, an appropriate alternate version of the file is provided with the sample. This is basically what you would get by running the Visual Studio 2008 Conversion Wizard on the .NET 2.0 version of the sample, but it is provided so users who don't have Visual Studio 2008 installed can use the sample with .NET 3.5 with minimum effort. The error page also contains instructions covering this case.


