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.