BotDetect ASP.NET 1.1 CAPTCHA Troubleshooting C# Code Sample

This BotDetect ASP.NET CAPTCHA code sample shows how to use the BotDetect built-in 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 and How to log all BotDetect CAPTCHA validation attempts to a text file guides. It simulates an exception in BotDetect code and demonstrates how it can be logged and handled, as well as recording all validation attempt details.

Please Note

Since this example logs errors and validation attempt details to a text file in the server filesystem, it will only work in full trust environments.

Sample Project Location

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

You can also run it from the Start Menu:
Programs > Lanapsoft > BotDetect > ASP.NET 1.1 > v2.0 > Samples > C# BotDetect CAPTCHA Troubleshooting Sample.

Default.aspx

Full Source Code Listing

<%@ Page language="c#" Codebehind="Default.aspx.cs" 
  AutoEventWireup="false" Inherits="CSharpBotDetectDemo._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 Validation Logging</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>
        <div class="ValidationTroubleshooting">
            <p>All Captcha validation attempts will be logged to the 
              'debug.txt' file in the sample folder.</p>
        </div>
        <div class="Troubleshooting">
            <p>
                <asp:Label ID="DebugLabel" runat="server"></asp:Label>
            </p>
        </div>
    </fieldset>
    
    <fieldset id="TroubleshootingError">
        <legend><span id="TroubleshootingErrorLegend">CAPTCHA Error 
            Logging</span></legend>
        <div class="Troubleshooting">
            <p>Clicking 'Simulate Error' will throw a fake BotDetect 
              exception and log it to the 'error.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>

    <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

Beside the usual elements required 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.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace CSharpBotDetectDemo
{
    /// <summary>
    /// Summary description for _Default.
    /// </summary>
    public class _Default : System.Web.UI.Page
    {
        protected Lanap.BotDetect.Captcha 
            SampleCaptcha;
						
        protected System.Web.UI.WebControls.Button 
            ValidateButton;
						
        protected System.Web.UI.WebControls.TextBox 
            CodeTextBox;
						
        protected System.Web.UI.WebControls.Label 
            MessageIncorrectLabel;
						
        protected System.Web.UI.WebControls.Label 
            MessageCorrectLabel;
						
        protected System.Web.UI.WebControls.Button 
            CauseErrorButton;
						
        protected System.Web.UI.WebControls.Label 
            ErrorLabel;
						
        protected System.Web.UI.WebControls.Label 
            DebugLabel;
						
        #region Web Form Designer generated code
        override protected void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET 
            // Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        { 
            this.PreRender += 
                new System.EventHandler(this.Page_PreRender);
        }
        #endregion

        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.";

                DebugLabel.Visible = false;
                DebugLabel.Text = "A validation attempt has been logged. 
                    Please check the 'debug.txt' file.";
            }
						
            if (null != Session["error"])
            {
                ErrorLabel.Visible = true;
                MessageCorrectLabel.Visible = false;
                MessageIncorrectLabel.Visible = false;
                Session["error"] = null;
                DebugLabel.Visible = false;
            }
            else
            {
                ErrorLabel.Visible = false;
            }

            // clear user input on Reload button clicks
            string scriptTemplate = @"<script type='text/javascript'>
              function LBD_ClearUserInput() {{
                var LBD_textBox = document.getElementById('{0}');
                if(LBD_textBox) {{
                  LBD_textBox.value = '';
                }}
              }}
              LBD_RegisterHandler('PreReloadCaptchaImage', 
                LBD_ClearUserInput);
            </script>";
            ";
            string script = String.Format(scriptTemplate, 
              CodeTextBox.ClientID);
					
            if (!Page.IsClientScriptBlockRegistered(
                "CaptchaReloadClearInput"))
            {
              Page.RegisterClientScriptBlock("CaptchaReloadClearInput", 
                script);
            }

            // automatically lowercase user inpu
            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;
                }

                DebugLabel.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.cs

Full Source Code Listing

using System;
using System.Collections;
using System.ComponentModel;
using System.Web;
using System.Web.SessionState;

namespace CSharpBotDetectTroubleshootingDemo 
{
    /// <summary>
    /// Summary description for Global.
    /// </summary>
    public class Global : System.Web.HttpApplication
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        public Global()
        {
            InitializeComponent();
        }	

        protected void Application_Start(Object sender, EventArgs e)
        {

        }

        protected void Session_Start(Object sender, EventArgs e)
        {

        }

        protected void Application_BeginRequest(Object sender, 
            EventArgs e)
        {

        }

        protected void Application_EndRequest(Object sender, 
            EventArgs e)
        {

        }

        protected void Application_AuthenticateRequest(Object sender, 
            EventArgs e)
        {

        }

        protected void Application_Error(Object sender, EventArgs e)
        {
            Response.Redirect("Default.aspx");
        }

        protected void Session_End(Object sender, EventArgs e)
        {

        }

        protected void Application_End(Object sender, EventArgs e)
        {

        }

        #region Web Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        { 
            this.components = new System.ComponentModel.Container();
        }
        #endregion
    }
}

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" encoding="utf-8" ?>
<configuration>
    
  <configSections>
    <section name="log4net" 
      type="log4net.Config.Log4NetConfigurationSectionHandler, 
      log4net"/>
  </configSections>
	
  <!-- This section contains the log4net configuration settings -->
  <log4net debug="false">

    <!-- Errors are logged to a 'error.txt' file  -->
    <appender name="ErrorFileAppender" 
        type="log4net.Appender.FileAppender">
      <file value="error.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>

    <!-- Error logging is enabled, comment-out to disable -->
    <logger name="ErrorLogger">
      <level value="ERROR" />
      <appender-ref ref="ErrorFileAppender" />
    </logger>
	
    <!-- Debug info is logged to a 'debug.txt' file  -->
    <appender name="DebugFileAppender" 
        type="log4net.Appender.FileAppender">
      <file value="debug.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>

    <!-- Debug logging is enabled, comment-out to disable -->
    <logger name="DebugLogger">
      <level value="DEBUG" />
      <appender-ref ref="DebugFileAppender" />
    </logger>

  </log4net>	
	
  <system.web>
  
  <httpHandlers>
    <add verb="*" path="LanapCaptcha.aspx" 
      type="Lanap.BotDetect.CaptchaHandler, Lanap.BotDetect"/>
  </httpHandlers>
	
  <httpModules>
    <add type="Lanap.BotDetect.Troubleshooting.LoggingModule, 
      Lanap.BotDetect.Troubleshooting" name="LoggingModule"/>
  </httpModules>

  <!-- DYNAMIC DEBUG COMPILATION
    Set compilation debug="true" to enable ASPX debugging. Otherwise, 
    setting this value to false will improve runtime performance of 
    this application. Set compilation debug="true" to insert debugging 
    symbols (.pdb information) into the compiled page. Because this 
    creates a larger file that executes more slowly, you should set 
    this value to true only when debugging and to false at all other 
    times. For more information, refer to the documentation about 
    debugging ASP.NET files.
  -->
  <compilation 
    defaultLanguage="c#"
    debug="false"
  />

  <!-- CUSTOM ERROR MESSAGES
    Set customErrors mode="On" or "RemoteOnly" to enable custom error 
    messages, "Off" to disable. 
		
    Add <error> tags for each of the errors you want to handle.

    "On" Always display custom (friendly) messages.
		
    "Off" Always display detailed ASP.NET error information.
		
    "RemoteOnly" Display custom (friendly) messages only to users not 
      running on the local Web server. This setting is recommended for 
      security purposes, so that you do not display application detail 
      information to remote clients.
  -->
  <customErrors 
    mode="RemoteOnly" 
  /> 

  <!-- AUTHENTICATION 
    This section sets the authentication policies of the application. 
    Possible modes are "Windows", "Forms", "Passport" and "None".

    "None" No authentication is performed. 
		
    "Windows" IIS performs authentication (Basic, Digest, or 
    Integrated Windows) according to its settings for the 
    application. Anonymous access must be disabled in IIS. 
		
    "Forms" You provide a custom form (Web page) for users to 
    enter their credentials, and then you authenticate them 
    in your application. A user credential token is stored 
    in a cookie.
		
    "Passport" Authentication is performed via a centralized 
    authentication service provided by Microsoft that offers 
    a single logon and core profile services for member sites.
  -->
  <authentication mode="Windows" /> 

  <!-- AUTHORIZATION 
    This section sets the authorization policies of the 
    application. You can allow or deny access to application 
    resources by user or role. Wildcards: "*" mean everyone, 
    "?" means anonymous (unauthenticated) users.
  -->

  <authorization>
    <allow users="*" /> <!-- Allow all users -->
    <!-- 
    <allow users="[comma separated list of users]"
      roles="[comma separated list of roles]"/>
    <deny users="[comma separated list of users]"
      roles="[comma separated list of roles]"/>
    -->
  </authorization>

  <!-- APPLICATION-LEVEL TRACE LOGGING
    Application-level tracing enables trace log output for 
    every page within an application. 
    Set trace enabled="true" to enable application trace 
    logging. If pageOutput="true", the trace information 
    will be displayed at the bottom of each page. Otherwise, 
    you can view the application trace log by browsing the 
    "trace.axd" page from your web application root. 
  -->
  <trace
    enabled="false"
    requestLimit="10"
    pageOutput="false"
    traceMode="SortByTime"
    localOnly="true"
  />

  <!-- SESSION STATE SETTINGS
    By default ASP.NET uses cookies to identify which requests 
    belong to a particular session. If cookies are not available, 
    a session can be tracked by adding a session identifier to the 
    URL. To disable cookies, set sessionState cookieless="true".
  -->
  <sessionState 
    mode="InProc"
    stateConnectionString="tcpip=127.0.0.1:42424"
    sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
    cookieless="false" 
    timeout="20" 
  />

  <!-- GLOBALIZATION
    This section sets the globalization settings of the application. 
  -->
  <globalization 
    requestEncoding="utf-8" 
    responseEncoding="utf-8" 
  />
   
 </system.web>

</configuration>

Explanation

Beside the usual HttpHandler and Session State declarations required for all BotDetect CAPTCHA applications, two more elements are necessary to enable BotDetect built-in error logging. The first is the HttpModule registration in the <httpModules> section, which activates the special BotDetect LoggingModule.

The second necessary 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. Using the log4net configuration syntax, the <log4net> section setups an error logger writing exception details to a text file named error.txt and located in the same folded as the log4net.config file, and a debug logger writing Captcha validation attempt details to a text file named debug.txt.

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.

language: English Español Tiếng Việt