BotDetect ASP.NET 2.0 CAPTCHA Troubleshooting C# Code Sample

This sample shows how to use the BotDetect built-in error logging to troubleshoot CAPTCHA issues. It is equivalent to the result you will get if you are following the How to log internal BotDetect errors to a text file guide. It simulates an exception in BotDetect code and demonstrates how it can be logged and handled.

Sample Project Location

By default, this sample project is installed at
C:\Program Files\Lanapsoft\BotDetect\ASP.NET 2.0\v2.0\Samples\CSharpBotDetect2TroubleshootingDemo\.

You can also run it from the Start Menu:
Programs > Lanapsoft > BotDetect > ASP.NET 2.0 > v2.0 > Samples > C# BotDetect Troubleshooting 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" %>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" 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>
        <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 id="ValidationDiv">
            <asp:TextBox ID="CodeTextBox" runat="server">
            </asp:TextBox>
            <asp:Button ID="ValidateButton" runat="server" />
            <asp:Label ID="MessageCorrectLabel" runat="server">
            </asp:Label>
            <asp:Label ID="MessageIncorrectLabel" runat="server">
            </asp:Label>
        </div>
    </fieldset>
    <div id="Note">
        <span>NOTE: the Trial version will use "LANAP" instead of a 
          random code in 50% of renderings.</span>
    </div>
    <fieldset id="Troubleshooting">
        <legend><span id="TroubleshootingLegend">CAPTCHA 
            Troubleshooting</span></legend>
        <div class="Troubleshooting">
          <p>Clicking 'Simulate Error' will throw a fake BotDetect 
              exception and log it to the 'log.txt' file in the 
              sample folder.</p>
        </div>
        <asp:Button ID="CauseErrorButton" runat="server" 
            OnClick="CauseErrorButton_Click" />
        <div class="Troubleshooting">
            <p>
                <asp:Label ID="ErrorLabel" runat="server">
                </asp:Label>
            </p>
        </div>
    </fieldset>
    </form>
</body>
</html>

Explanation

Beside the usual elements requried to add the BotDetect CAPTCHA to an ASP.NET form, this file also contains an extra button used to simulate an internal BotDetect exception and several related presentation elements.

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_PreRender(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;

            CauseErrorButton.Text = "Simulate error";
            ErrorLabel.Text = "An error has been generated. 
                Please check the 'error.log' file.";
        }

        if (null != Session["error"])
        {
            ErrorLabel.Visible = true;
            MessageCorrectLabel.Visible = false;
            MessageIncorrectLabel.Visible = false;
            Session["error"] = null;
        }
        else
        {
            ErrorLabel.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;
        }
    }

    protected void CauseErrorButton_Click(object sender, EventArgs e)
    {
        Session["error"] = true;
        throw new Lanap.BotDetect.Exceptions.CaptchaWebException(
            "Simulated exception");
    }
}

Explanation

Beside the usual CAPTCHA initialization and validation code, the CauseErrorButton_Click event handler is used to throw a simulated BotDetect internal exception. Since this is a simplified sample project containing only one page which is used both before and after the exception is thrown and handled, we also use a Session flag to handle error information presentation.

There is no error handling code in the form codebehind, since a special HttpModule is registered in the Web.config file, which catches BotDetect internal errors (but not general exceptions) and writes the error information to a text file.

Global.asax

Full Source Code Listing

<%@ Application Language="C#" %>

<script runat="server">

    void Application_Start(object sender, EventArgs e) 
    {
        // Code that runs on application startup

    }
    
    void Application_End(object sender, EventArgs e) 
    {
        //  Code that runs on application shutdown

    }
        
    void Application_Error(object sender, EventArgs e) 
    { 
        // Code that runs when an unhandled error occurs
        Response.Redirect("Default.aspx");

    }

    void Session_Start(object sender, EventArgs e) 
    {
        // Code that runs when a new session is started

    }

    void Session_End(object sender, EventArgs e) 
    {
        // Code that runs when a session ends. 
        // Note: The Session_End event is raised only when the 
        // sessionstate mode is set to InProc in the Web.config file. 
        // If session mode is set to StateServer or SQLServer, 
        // the event is not raised.
				
    }
       
</script>

Explanation

Since the BotDetect internal error logging re-throws any exceptions after logging their details, you can handle all exceptions in your applications in a consistent manner. In this simple example, we just ignore the error and redraw the only page in the application.

Web.config

Full Source Code Listing

<?xml version="1.0"?>
<!-- 
    Note: As an alternative to hand editing this file you can use the 
    web admin tool to configure settings for your application. Use
    the Website->Asp.Net Configuration option in Visual Studio.
    A full list of settings and comments can be found in 
    machine.config.comments usually located in 
    \Windows\Microsoft.Net\Framework\v2.x\Config 
-->
<configuration>
  <configSections>
    <section name="log4net" 
      type="log4net.Config.Log4NetConfigurationSectionHandler, 
      log4net"/>
  </configSections>
  <log4net configSource="log4net.config"/>
  <connectionStrings/>
  <system.web>
    <httpHandlers>
      <add verb="*" path="LanapCaptcha.aspx" 
        type="Lanap.BotDetect.CaptchaHandler, Lanap.BotDetect"/>
    </httpHandlers>
    <httpModules>
      <add type="Lanap.BotDetect.Troubleshooting.ErrorTrackingModule, 
        Lanap.BotDetect.Troubleshooting" name="ErrorTrackingModule"/>
    </httpModules>
    <sessionState mode="InProc" cookieless="AutoDetect" timeout="20" 
      sessionIDManagerType="Lanap.BotDetect.Persistence.
      CustomSessionIDManager, Lanap.BotDetect" />
    <!-- 
      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.Design, Version=2.0.0.0, 
          Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
      </assemblies>
    </compilation>
    <!--
      The <authentication> section enables configuration 
      of the security authentication mode used by 
      ASP.NET to identify an incoming user. 
    -->
    <authentication mode="None"/>
    <!--
      The <customErrors> section enables configuration 
      of what to do if/when an unhandled error occurs 
      during the execution of a request. Specifically, 
      it enables developers to configure html error pages 
      to be displayed in place of a error stack trace.

      <customErrors mode="RemoteOnly" 
        defaultRedirect="GenericErrorPage.htm">
        <error statusCode="403" redirect="NoAccess.htm" />
        <error statusCode="404" redirect="FileNotFound.htm" />
      </customErrors>
    -->
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <remove name="LanapCaptchaHandler" />
      <add name="LanapCaptchaHandler" preCondition="integratedMode" 
        verb="*" path="LanapCaptcha.aspx" 
        type="Lanap.BotDetect.CaptchaHandler, Lanap.BotDetect" />
    </handlers>
    <modules>
      <remove name="ErrorTrackingModule" />
      <add name="ErrorTrackingModule" 
        preCondition="integratedMode" 
        type="Lanap.BotDetect.Troubleshooting.ErrorTrackingModule, 
        Lanap.BotDetect.Troubleshooting" />
    </modules>
  </system.webServer>
</configuration>

Explanation

Beside the usual HttpHandler and Session State declarations required for all BotDetect CAPTCHA applications, two more elements are neccesary to enable BotDetect built-in error logging. The first is the HttpModule registration in the <httpModules> section, which activates the special BotDetect ErrorTrackingModule. To support IIS 7.0 machines configured to run the ASP.NET runtime in the Integrated Mode, this same registration is repeated in the <system.webServer> <modules> section, similar to how the HttpHandler registration is repeated in the <handlers> section.

The second neccesary element is the <configSection> declaration, in which we register a special configuration section for log4net (the open-source .NET logging framework used for the actual error logging) settings. To simplify matters, this configuration section is set to be loaded from an external .config file.

Log4net.config

Full Source Code Listing

<?xml version="1.0"?>

<!-- This section contains the log4net configuration settings -->
<log4net debug="false">

  <!-- Define some output appenders -->

  <appender name="FileAppender" type="log4net.Appender.FileAppender">
    <file value="log.txt" />
    <appendToFile value="true" />
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <layout type="log4net.Layout.PatternLayout,log4net">
      <conversionPattern 
        value="%date [%thread] %type - %n%n%message%n%n" />
    </layout>
  </appender>

  <!-- Setup the root category, add the appenders and set 
    the default priority -->

  <logger name="ErrorLogger">
    <level value="ERROR" />
    <appender-ref ref="FileAppender" />
  </logger>

</log4net>

Explanation

Using the log4net configuration syntax, this file setups an error logger writing exception details to a text file named log.txt and located in the same folded as the log4net.config file. The log4net framework offers many other logging options, from different log output destinations to different log message levels (trace, debug, and other messages), which can be handled in different ways. For simplicity's sake, this sample project uses a simple file logger – if you are interested in the other options, please consult the log4net documentation.