ASP.NET MVC Single Page Application CAPTCHA VB.NET Code Example

The ASP.NET MVC Single Page Application Captcha VB.NET example project shows the most basic source code required to protect an ASP.NET MVC form with BotDetect CAPTCHA and validate the user input.

First Time Here?

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

ASP.NET MVC View code displaying CAPTCHA protection can be found in Views/Account/Register.vbhtml, and the ASP.NET MVC Controller code checking user input is in Controllers/AccountController.vb.

Download the BotDetect ASP.NET CAPTCHA Component and run this example

→ .NET programming language:

  • C#
  • VB.NET

Installed Location

By default, the .NET VB.NET version of the ASP.NET MVC Single Page Application Captcha example project is installed at:
C:\Program Files\Captcha Inc\BotDetect CAPTCHA\aspnetlegacy+netlegacy\Examples\TraditionalAPI\MvcSinglePageAppCaptchaExample\VBNet

You can also run it from the BotDetect Start Menu:
Programs > Captcha Inc > BotDetect CAPTCHA > ASPNETLEGACY + NETLEGACY Examples > Legacy ASP.NET + Legacy .NET Run code examples

Views\Account\Register.vbhtml

@ModelType RegisterViewModel 
@* namespaces needed to access BotDetect members and the CaptchaHelper class *@ 
@Imports BotDetect.Web.Mvc 
@Code 
    ViewBag.Title = "Register" 
End Code 

<h2>@ViewBag.Title.</h2> 

@* include BotDetect layout stylesheet in page <head> *@ 
@Section HeadIncludes 
    <link href="@BotDetect.Web.CaptchaUrls.Absolute.LayoutStyleSheetUrl" 
    rel="stylesheet" type="text/css" /> 
End Section 

@Using Html.BeginForm("Register", "Account", FormMethod.Post, New With {.class = 
"form-horizontal", .role = "form"}) 

    @Html.AntiForgeryToken() 

    @<text> 
        <h4>Create a new account.</h4> 
        <hr /> 
        <div class="col-md-6" id="form-container"> 
            @Html.ValidationSummary("", New With {.class = "text-danger"}) 
            <div class="form-group"> 
                @Html.LabelFor(Function(m) m.Email, New With {.class = "col-md-2  
                control-label"}) 
                <div class="col-md-10"> 
                    @Html.TextBoxFor(Function(m) m.Email, New With {.class = 
                    "form-control"}) 
                </div> 
            </div> 
            <div class="form-group"> 
                @Html.LabelFor(Function(m) m.Hometown, New With {.class = "col- 
                md-2 control-label"}) 
                <div class="col-md-10"> 
                    @Html.TextBoxFor(Function(m) m.Hometown, New With {.class = 
                    "form-control"}) 
                </div> 
            </div> 
            <div class="form-group"> 
                @Html.LabelFor(Function(m) m.Password, New With {.class = "col- 
                md-2 control-label"}) 
                <div class="col-md-10"> 
                    @Html.PasswordFor(Function(m) m.Password, New With {.class = 
                    "form-control"}) 
                </div> 
            </div> 
            <div class="form-group"> 
                @Html.LabelFor(Function(m) m.ConfirmPassword, New With {.class = 
                "col-md-2 control-label"}) 
                <div class="col-md-10"> 
                    @Html.PasswordFor(Function(m) m.ConfirmPassword, New With {. 
                    class = "form-control"}) 
                </div> 
            </div> 
            @* showing Captcha on the form: 
                add Captcha validation controls to the protected action View, 
                but only if the Captcha hasn't already been solved *@ 

            @Code Dim registrationCaptcha As MvcCaptcha = CaptchaHelper.GetRegistrationCaptcha() 
                If (Not registrationCaptcha.IsSolved) Then 
                    @<div class="form-group"> 
                        <div class="col-md-offset-2 col-md-10"> 
                            @Html.Captcha(registrationCaptcha) 
                        </div> 

                        @Html.Label("Retype the code", New With {.class = "col- 
                        md-2 control-label"}) 

                        <div class="col-md-10"> 
                            @Html.TextBox("CaptchaCode", Nothing, New With {. 
                            class = "form-control captchaVal"}) 
                        </div> 
                    </div> 
                End If 
            End Code 
            <div class="form-group"> 
                <div class="col-md-offset-2 col-md-10"> 
                    <input type="submit" class="btn btn-default" 
                    value="Register" /> 
                </div> 
            </div> 
        </div> 
    </text> 
                End Using 

@section Scripts 
    @Scripts.Render("~/bundles/jqueryval") 
End Section 

To display Captcha protection on the example View, we first ensure we can use BotDetect members by Import-ing the relevant namespaces.

We then create a MvcCaptcha instance, and add it to the form by calling the Html.Captcha() Html helper with it.

In this simplest case, we also use the Html.ValidationMessage helper to display Captcha validation errors.

Controllers\AccountController.vb

Imports System.Security.Claims 
Imports System.Threading.Tasks 
Imports Microsoft.AspNet.Identity 
Imports Microsoft.AspNet.Identity.Owin 
Imports Microsoft.Owin.Security 
Imports BotDetect.Web.Mvc 

<Authorize> 
Public Class AccountController 
    Inherits Controller 
    Private _signInManager As ApplicationSignInManager 
    Private _userManager As ApplicationUserManager 

    Public Sub New() 
    End Sub 

    Public Sub New(appUserMan As ApplicationUserManager, signInMan As 
    ApplicationSignInManager) 
        UserManager = appUserMan 
        SignInManager = signInMan 
    End Sub 

    [..] 

    ' 
    ' GET: /Account/Register 
    <AllowAnonymous> 
    Public Function Register() As ActionResult 
        Return View() 
    End Function 

    ' 
    ' POST: /Account/Register 
    <HttpPost> 
    <AllowAnonymous> 
    <ValidateAntiForgeryToken> 
    <CaptchaValidation("CaptchaCode", "RegistrationCaptcha", "Incorrect CAPTCHA Code!")> 
    Public Async Function Register(model As RegisterViewModel) As Task(Of 
    ActionResult) 
        If ModelState.IsValid Then 
            Dim user = New ApplicationUser() With { 
                .UserName = model.Email, 
                .Email = model.Email, 
                .Hometown = model.Hometown 
            } 
            Dim result = Await UserManager.CreateAsync(user, model.Password) 
            If result.Succeeded Then 
                Await SignInManager.SignInAsync(user, isPersistent:=False, 
                rememberBrowser:=False) 

                ' For more information on how to enable account confirmation and  
                password reset please visit http://go.microsoft. 
                com/fwlink/?LinkID=320771 
                ' Send an email with this link 
                ' Dim code = Await UserManager. 
                GenerateEmailConfirmationTokenAsync(user.Id) 
                ' Dim callbackUrl = Url.Action("ConfirmEmail", "Account", New  
                With { .userId = user.Id, .code = code }, protocol := Request. 
                Url.Scheme) 
                ' Await UserManager.SendEmailAsync(user.Id, "Confirm your  
                account", "Please confirm your account by clicking <a href=""" &  
                callbackUrl & """>here</a>") 
                MvcCaptcha.ResetCaptcha("RegistrationCaptcha") 
                Return RedirectToAction("Index", "Home") 
            End If 
            AddErrors(result) 
        End If 

        ' If we got this far, something failed, redisplay form 
        Return View(model) 
    End Function 

    [..] 
End Class 

After we've included the BotDetect.Web.Mvc namespace, we just need to add the CaptchaValidation attribute to the method processing form submissions. The attribute takes three parameters:

  1. the ID of the textbox containing the user's Captcha code input (which we named CaptchaCode on the form),
  2. the ID of the Captcha instance we're validating (which we set to ExampleCaptcha in the MvcCaptcha constructor), and
  3. the error message to be shown when Captcha validation fails.

When the Captcha validation action filter attribute has been added, the Captcha validation will trigger every time the form is submitted, and will automatically add a Model error with the error message configured above when Captcha validation fails. The Html.ValidationMessage helper on the form will then display this error when Captcha validation fails.

App_Start\RouteConfig.vb

Imports System 
Imports System.Collections.Generic 
Imports System.Linq 
Imports System.Web 
Imports System.Web.Mvc 
Imports System.Web.Routing 

Public Module RouteConfig 
  Public 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"}) 

    routes.MapRoute( _ 
        name:="Default", _ 
        url:="{controller}/{action}/{id}", _ 
        defaults:=New With {.controller = "Example", .action = "Index", . 
        id = UrlParameter.Optional} _ 
    ) 
  End Sub 
End Module 

We configure ASP.NET Routing to ignore BotDetect requests, since they do not conform to any MVC-related patterns. The regex defining requests to ignore must match the path configured for the BotDetect HttpHandler registered in web.config.

Web.config

<?xml version="1.0" encoding="utf-8"?> 
<!-- 
  For more information on how to configure your ASP.NET application, please  
  visit 
  http://go.microsoft.com/fwlink/?LinkId=301879 
  --> 
<configuration> 
  <configSections> 
    <!-- For more information on Entity Framework configuration, visit http://go. 
    microsoft.com/fwlink/?LinkID=237468 --> 
    <section name="botDetect" requirePermission="false" 
    type="BotDetect.Configuration.BotDetectConfigurationSection, BotDetect"/> 
  </configSections> 
  <connectionStrings> 
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb) 
    \MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-CSharp-20150616040032. 
    mdf;Initial Catalog=aspnet-CSharp-20150616040032;Integrated Security=True" 
      providerName="System.Data.SqlClient" /> 

  </connectionStrings> 
  <appSettings> 
    <add key="webpages:Version" value="3.0.0.0" /> 
    <add key="webpages:Enabled" value="false" /> 
    <add key="ClientValidationEnabled" value="true" /> 
    <add key="UnobtrusiveJavaScriptEnabled" value="true" /> 
  </appSettings> 
  <system.web> 
    <authentication mode="None" /> 
    <compilation debug="true" targetFramework="4.6" /> 
    <httpRuntime targetFramework="4.6" /> 
    <!-- configure Session State for BotDetect use --> 
    <sessionState mode="InProc" cookieless="AutoDetect" timeout="20" 
    sessionIDManagerType="BotDetect.Web.CustomSessionIdManager, BotDetect"/> 
    <httpHandlers> 
      <!-- register HttpHandler used for BotDetect Captcha requests --> 
      <add verb="GET" path="BotDetectCaptcha.ashx" 
      type="BotDetect.Web.CaptchaHandler, BotDetect"/> 
    </httpHandlers> 
  </system.web> 
  <system.webServer> 
    <validation validateIntegratedModeConfiguration="false"/> 
    <modules> 
      <remove name="FormsAuthentication" /> 
    </modules> 
    <handlers> 
      <!-- 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"/> 
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> 
      <remove name="OPTIONSVerbHandler" /> 
      <remove name="TRACEVerbHandler" /> 
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" 
      type="System.Web.Handlers.TransferRequestHandler" 
      preCondition="integratedMode,runtimeVersionv4.0" /> 
    </handlers> 
  </system.webServer> 
  <runtime> 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
      <dependentAssembly> 
        <assemblyIdentity name="Microsoft.Owin" 
        publicKeyToken="31bf3856ad364e35" /> 
        <bindingRedirect oldVersion="1.0.0.0-3.0.1.0" newVersion="3.0.1.0" /> 
      </dependentAssembly> 
      <dependentAssembly> 
        <assemblyIdentity name="Microsoft.Owin.Security.OAuth" 
        publicKeyToken="31bf3856ad364e35" /> 
        <bindingRedirect oldVersion="1.0.0.0-3.0.1.0" newVersion="3.0.1.0" /> 
      </dependentAssembly> 
      <dependentAssembly> 
        <assemblyIdentity name="Microsoft.Owin.Security.Cookies" 
        publicKeyToken="31bf3856ad364e35" /> 
        <bindingRedirect oldVersion="1.0.0.0-3.0.1.0" newVersion="3.0.1.0" /> 
      </dependentAssembly> 
      <dependentAssembly> 
        <assemblyIdentity name="Microsoft.Owin.Security" 
        publicKeyToken="31bf3856ad364e35" /> 
        <bindingRedirect oldVersion="1.0.0.0-3.0.1.0" newVersion="3.0.1.0" /> 
      </dependentAssembly> 
      <dependentAssembly> 
        <assemblyIdentity name="Newtonsoft.Json" culture="neutral" 
        publicKeyToken="30ad4fe6b2a6aeed" /> 
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" /> 
      </dependentAssembly> 
      <dependentAssembly> 
        <assemblyIdentity name="System.Web.Optimization" 
        publicKeyToken="31bf3856ad364e35" /> 
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" /> 
      </dependentAssembly> 
      <dependentAssembly> 
        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" /> 
        <bindingRedirect oldVersion="1.0.0.0-1.5.2.14234" newVersion="1.5.2. 
        14234" /> 
      </dependentAssembly> 
      <dependentAssembly> 
        <assemblyIdentity name="System.Web.Helpers" 
        publicKeyToken="31bf3856ad364e35" /> 
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" /> 
      </dependentAssembly> 
      <dependentAssembly> 
        <assemblyIdentity name="System.Web.WebPages" 
        publicKeyToken="31bf3856ad364e35" /> 
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" /> 
      </dependentAssembly> 
      <dependentAssembly> 
        <assemblyIdentity name="System.Web.Mvc" 
        publicKeyToken="31bf3856ad364e35" /> 
        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" /> 
      </dependentAssembly> 
    </assemblyBinding> 
  </runtime> 
  <botDetect helpLinkEnabled="true" helpLinkMode="image" /> 
</configuration> 

To allow the application to use BotDetect Captcha protection, we must register the BotDetect HttpHandler in both <system.web><httpHandlers> and <system.webServer><handlers> configuration sections, and enable and configure ASP.NET sessionState.

The <dependentAssembly> entry for System.Web.Mvc is also needed to make all ASP.NET MVC dependencies referenced by the BotDetect MVC assembly point to the correct ASP.NET MVC version.