How To Add BotDetect CAPTCHA Protection to ASP.NET MVC 5.0 Applications

BotDetect ASP.NET Captcha protection can be added to your ASP.NET MVC 5.0 applications using the MvcCaptcha class, a BotDetect HtmlHelper and a custom ActionFilterAttribute implemented in the BotDetect.Web.Mvc.dll assembly.

First Time Here?

Check the BotDetect ASP.NET MVC Captcha Quickstart for key integration steps.

You can also see how BotDetect Captcha protection has been added to the starting ASP.NET MVC application by running the BotDetect Captcha ASP.NET MVC integration code examples coming with the BotDetect installation.

You can reuse the example projects source code (available for both C# and VB.NET) that fits your application requirements.

CAPTCHA Integration Steps

When adding BotDetect CAPTCHA to an ASP.NET MVC 5.0 application:
  1. Display a Captcha challenge on the Asp.Net MVC View
  2. Check is the visitor a human in the Controller action
  3. Further Captcha customization and options

I. Display a CAPTCHA Challenge on the ASP.NET MVC View

Before protecting a Controller action in your ASP.NET MVC application with BotDetect Captcha, you should decide how to call the Captcha instance and the related textbox you will use. In this guide, we will use ExampleCaptcha and CaptchaCode. If you plan to protect multiple Controller actions within the same ASP.NET MVC application, you should take care to give each Captcha instance a different name (e.g. LoginCaptcha, RegisterCaptcha, CommentCaptcha etc.).

You will also need to register a HttpHandler that will handle Captcha requests, and exclude it from ASP.NET Routing.

Reference BotDetect Assemblies

ASP.NET MVC applications should reference both the base BotDetect.dll assembly and the ASP.NET MVC-specific BotDetect.Web.Mvc.dll assembly. If you didn't change the installation folder during BotDetect setup, they can both be found in the C:\Program Files (x86)\Captcha Inc\BotDetect 4 CAPTCHA Component\Asp.Net\.NET4.5\ folder.

Resolving ASP.NET MVC Dependencies

The same BotDetect assembly will work with all versions of ASP.NET MVC (for example, ASP.NET MVC 3.0, ASP.NET MVC 4.0, ASP.NET MVC 5.0 etc.). However, since the BotDetect assembly can only be built with a reference to a single ASP.NET MVC version, you might get runtime errors if the version of ASP.NET MVC you are using doesn't match the one BotDetect was built with.

Fortunatelly, it is easy to resolve these errors with a binding redirect in your web.config file:
<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
      <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

Just specify the ASP.NET MVC version you are using in the newVersion configuration attribute, and any MVC dependency-related errors should be resolved.

Create and Render a BotDetect.Web.Mvc.MvcCaptcha Instance

Captcha objects in ASP.NET MVC applications are represented by the MvcCaptcha class, and they can be rendered using a HtmlHelper extension method defined in the same assembly. To use them, your View should first import the BotDetect.Web.Mvc namespace.

Then, you can add a Captcha challenge to the View by rendering a Html.Label with the Captcha instructions for the user, a Html.Captcha with the MvcCaptcha object instance, and a Html.TextBox in which the user is to type the Captcha code:

@using BotDetect.Web.Mvc;

  […]

@Html.Label("CaptchaCode", "Retype the code from the picture:")
@{ MvcCaptcha exampleCaptcha = new MvcCaptcha("ExampleCaptcha"); }
@Html.Captcha(exampleCaptcha)
@Html.TextBox("CaptchaCode")

(Option) Encapsulate MvcCaptcha Instance Creation in a Helper Class

Since the MvcCaptcha object exposes a number of Captcha properties, the code that initializes it will often grow much longer than a single line with the constructor call (as shown in the View code above).

Adding those additional lines directly to the View would add unnecessary length and complexity to View code, and mixing code that deals with different concerns (View composition and Captcha object initialization in this case) is never a good practice. It is a much better idea to separate Captcha object creation in a specialized helper class, and keep MvcCaptcha instance access in a single line of View code.

For example, if you added the following class declaration to your ASP.NET MVC application's App_Code folder:

[C#]

public static class CaptchaHelper
{
    public static MvcCaptcha GetExampleCaptcha()
    {
        // create the control instance
        MvcCaptcha exampleCaptcha = new MvcCaptcha("ExampleCaptcha");

        // set up client-side processing of the Captcha code input textbox
        exampleCaptcha.UserInputID = "CaptchaCode";

        return exampleCaptcha;
    }
}
[VB.NET]

Public Class CaptchaHelper

    Public Shared Function GetExampleCaptcha() As MvcCaptcha

        ' create the control instance
        Dim exampleCaptcha As MvcCaptcha = New MvcCaptcha("ExampleCaptcha")

        ' set up client-side processing of the Captcha code input textbox
        exampleCaptcha.UserInputID = "CaptchaCode"

        Return exampleCaptcha

    End Function

End Class

you could replace the exampleCaptcha = new MvcCaptcha("ExampleCaptcha") call in your View code with exampleCaptcha = CaptchaHelper.GetExampleCaptcha(). That way, the code initializing the Captcha object can grow arbitrarily large without cluttering the View. Of course, you would also need to import your application's namespace in the View to be able to access the CaptchaHelper class.

Include the BotDetect CAPTCHA Layout StyleSheet

Since the Html markup generated by BotDetect includes a number of different elements (the Captcha image, the icons for Captcha reloading and Captcha sound playing, the Captcha help link etc.), there are some CSS declarations which need to be included for those elements to display correctly.

The best place to include CSS style declarations is in the page <head>, and since you are controlling the View markup, you know best where exactly to add them. The BotDetect layout stylesheet can be included with the following declaration:

<link href="@BotDetect.Web.CaptchaUrls.Absolute.LayoutStyleSheetUrl"
      rel="stylesheet" type="text/css" />

If your View generates its own <head> section, you can add these declaration directly in View code. If you're using a Razor Layout and individual Views only generate main content, you can add them to the Razor Layout.

Even better, your layout can include a @RenderSection() – and then individual Views can add their required declarations there without affecting other Views. You can see an example of this last approach in the BotDetect ASP.NET MVC Captcha code example Views.

Register the BotDetect HttpHandler for CAPTCHA Requests

BotDetect uses a special HttpHandler for Captcha requests (Captcha images, sounds, resources...), which needs to be registered in your application before Captcha images will be displayed. This registration is a three-step process:

1. Base HttpHandler Registration

  • Locate the <system.web> -> <httpHandlers> section of the web.config file.
  • Add the following BotDetect handler registration to this section:
    <!-- Register the HttpHandler used for BotDetect Captcha requests -->
    <add verb="GET" path="BotDetectCaptcha.ashx" 
        type="BotDetect.Web.CaptchaHandler, BotDetect"/>

2. IIS 7.0+ HttpHandler Registration

  • Locate the <system.webServer> -> <handlers> section of the web.config file.
  • Add the following BotDetect handler registration to this section:
    <!-- Register the HttpHandler used for BotDetect Captcha requests
      (IIS 7.0+) -->
    <remove name="BotDetectCaptchaHandler"/>
    <add name="BotDetectCaptchaHandler" preCondition="integratedMode"
        verb="GET" path="BotDetectCaptcha.ashx"
        type="BotDetect.Web.CaptchaHandler, BotDetect"/>

3. Exclude BotDetect HttpHandler Requests From ASP.NET Routing

Once the BotDetect Captcha HttpHandler is registered in your application's Web.config file, you will also need to exclude it from ASP.NET Routing. Since routing rules try to map all incoming requests to a Controller/Action/Params pattern, and BotDetect requests do not match it, Captcha images will not display correctly until routing rules are told to ignore BotDetect requests.

Go to your application's App_Start/RouteConfig.cs (or App_Start/RouteConfig.vb) file and add the following bolded line:

[C#]
    
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    // BotDetect requests must not be routed
    routes.IgnoreRoute("{*botdetect}", 
      new { botdetect = @"(.*)BotDetectCaptcha\.ashx" });
      
    […]
    
[VB.NET]

Public Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

    ' BotDetect requests must not be routed
    routes.IgnoreRoute("{*botdetect}", 
      New With {.botdetect = "(.*)BotDetectCaptcha\.ashx"})    
      
    […]
    

Once all of these steps have been performed, the Captcha should be displayed when you open your form in a browser:

BotDetect CAPTCHA added to an ASP.NET form

If the Captcha image isn't being rendered properly, please check the BotDetect integration FAQ.

II. Check is the Visitor a Human in the Controller Action

Once the Captcha challenge is displayed on your View, the Controller code processing submissions can check if the Captcha was solved successfully and deny access to bots.

Captcha validation is encapsulated within an ActionFilterAttribute that can be added to actions accepting HtppVerbs.Post requests; the CaptchaValidation attribute just needs to be passed the names of the Captcha instance and Captcha code textbox used. ASP.NET Session state must also be enabled before Captcha validation can work.

Mark the Protected Controller Action with the CaptchaValidation Attribute

The CaptchaValidation attribute takes three parameters:

  • Captcha code textbox name
  • MvcCaptcha instance name
  • the error message that will be displayed when Captcha validation fails
[C#]

//
// POST: /ExampleController/ExampleAction

[HttpPost]
[AllowAnonymous]
[CaptchaValidation("CaptchaCode", "ExampleCaptcha", "Incorrect CAPTCHA code!")]
public ActionResult ExampleAction(ExampleModel model)
{
    if (ModelState.IsValid)
    {    
    
        […]
        
        // You should call ResetCaptcha as demonstrated in the following example.
        MvcCaptcha.ResetCaptcha("ExampleCaptcha");

        […]
    
[VB.NET]

'
' POST: /ExampleController/ExampleAction

<HttpPost()> _
<AllowAnonymous()> _
<CaptchaValidation("CaptchaCode", "ExampleCaptcha", "Incorrect CAPTCHA code!")> _
Public Function ExampleAction(ByVal model As ExampleModel) As ActionResult
    
    If ModelState.IsValid Then
    
        […]
        
        // You should call ResetCaptcha as demonstrated in the following example.
        MvcCaptcha.ResetCaptcha("ExampleCaptcha")
    
        […]

If everything has been configured correctly, the above ActionFilterAttribute will automatically add the appropriate ModelState error when Captcha validation fails, and checking ModelState validity will include the Captcha validation result.

If you are using a validation summary to display Model validation errors, the Captcha validation error will be displayed there as well. If, on the other hand, you are displaying individual server-side validation errors one by one, you can always get the Captcha validation error in your View by the Captcha code textbox name. For example, Html.ValidationMessage("CaptchaCode") added to the above View code will be empty if Captcha validation succeeded, and will contain the error message defined in the CaptchaValidation attribute if Captcha validation fails.

Configure ASP.NET Session State

BotDetect Captcha validation requires ASP.NET Session state – generated random Captcha codes have to be stored on the server and compared to the user input. Also, to ensure Captcha sounds work properly in all browsers, a custom SessionIDManager (implementing an optional but recommended improvement) should be registered.

  • In the <system.web> section of the web.config file, locate the <pages> element and set the enableSessionState attribute:
    <pages enableSessionState="true">
  • In the <system.web> section of the web.config file, locate the <sessionState> element if it exists, or add it if it doesn't.
  • Add the following attribute to the declaration:
    sessionIDManagerType="BotDetect.Web.CustomSessionIdManager, BotDetect"
The most common resulting declaration would be:
<sessionState mode="InProc" cookieless="AutoDetect" timeout="20"
    sessionIDManagerType="BotDetect.Web.CustomSessionIdManager, BotDetect"/>

You can use a different Session State mode or options, since BotDetect works with all of them. For more information about BotDetect and ASP.NET Session state, and debugging tips in case the Captcha validation is failing even when you type the correct Captcha code, please check the BotDetect persistence options FAQ.

(Option) CAPTCHA Validation Separate From Model State Validation

If, for any reason, you want to check Captcha validity separately from ModelState, you can simply use an additional action parameter (which must be called captchaValid) and make the validation logic explicit:

[C#]
    
[CaptchaValidation("CaptchaCode", "ExampleCaptcha", "Incorrect CAPTCHA code!")]
public ActionResult ExampleAction(ExampleModel model, bool captchaValid)
{
    if (captchaValid)
    {
    
        […]

[VB.NET]

<CaptchaValidation("CaptchaCode", "ExampleCaptcha", "Incorrect CAPTCHA code!")> _
Public Function ExampleAction(ByVal model As ExampleModel, _
    ByVal captchaValid As Boolean) As ActionResult
   
    If captchaValid Then
    
        […]
    

(Option) Client-Side CAPTCHA Validation

Since the Captcha codes must be stored and checked on the server, pure client-side Captcha validation is not feasible (as explained in the BotDetect FAQ). However, it is possible to improve the usability of your form with Ajax Captcha validation.

CAPTCHA Validation Using ASP.NET MVC 5.0 Unobtrusive Validation

If you're using ASP.NET MVC 4.0 unobtrusive validation, adding the same for Captcha code fields is as simple as adding a few validation configuration rules in a JavaScript include added after the "~/bundles/jqueryval" ASP.NET MVC script bundle. An example is given in the ASP.NET MVC 5.0 Internet application Captcha example.

CAPTCHA Validation Using jQuery and JsonResult Controller Actions

Another MVC-specific way to implement Ajax Captcha validation is to combine jQuery $.getJSON Ajax requests on the client with the ASP.NET MVC Controller actions with the JsonResult return type. An example is given in the ASP.NET MVC 5.0 jQuery Ajax Captcha example.

CAPTCHA Validation Using the jQuery Validate Plugin

If you are using your own field validation functionality based on the jquery.validate.js plugin, client-side Captcha validation can be implemented using a combination of the required and remote validation rules. An example is given in the ASP.NET jQuery Validation Captcha example.

III. Further CAPTCHA Customization and Options

BotDetect ASP.NET Captcha allows detailed customization of many Captcha properties, and you can read more about them in the BotDetect Captcha configuration How To.