reCAPTCHA with update panels

Using Google's reCaptcha with ajaxToolKit:ToolkitScriptManager and asp:UpdatePanel

Recaptcha not working in asp.net?  Are you using panels?  The problem is the dynamic nature of the panel content.  If your recaptcha field is inside a panel you cannot use traditional javascript snippets - the reCaptcha will only render if the panel is rendered at page load, and if any click functions update the panel[s] the recaptcha is destroyed.

ALL postbacks will erase your reCaptcha field, and what if you don't even have the reCaptcha field showing on page load?

The solution is to use the render=explicit option, with targets in your panel[s], then in the codebehind add script to call grecaptcha.render() any time the panel[s] with the reCaptcha are required.

The following method will [re]render the captcha field on demand.  The verification routine is also here for your enjoyment.  Feel free to put the reCaptcha methods in a class for re-use on other pages.

This was built/tested on VS2012.

Shared.master

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Shared.master.cs" Inherits="Shared.NameSpace" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolKit" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Recaptcha AjaxControl Panel[s]</title>

        <!-- Load google asap, as window.grecaptcha takes some time to be available -->
        <!-- of course, you will likely load these conditionally with a placeholder -->
        <script type="text/javascript" src="https://www.google.com/recaptcha/api.js?render=explicit"></script>
        <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
        <script type="text/javascript" src="/Shared/validation.js"></script>

    </head>
<body>
    <form id="form1" runat="server">
        <ajaxToolKit:ToolkitScriptManager ID="tkScriptManager1" runat="server" CombineScripts="true" ScriptMode="Release" EnablePartialRendering="true" LoadScriptsBeforeUI="false" EnablePageMethods="true" />
        <asp:ContentPlaceHolder ID="MainContent" runat="server"></asp:ContentPlaceHolder>
    </form>
</body>
</html>

page.aspx

<asp:Content ID="ContentMain" ContentPlaceHolderID="MainContent" runat="server">
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>

            <asp:Panel ID="pnlMain" Visible="true" runat="server">
                <asp:LinkButton ID="linkToSecondary" OnClick="linkToSecondary_Click" Text="Secondary Panel" runat="server" />
                <fieldset>
                    <div class="field field-captcha">
                        <div id="reCaptchaMain" class="g-recaptcha" data-sitekey="<%=reCAPTCHA_Site_key%>" data-theme="<%=reCAPTCHA_theme%>" data-size="<%=reCAPTCHA_size%>"></div>
                        <asp:Label ID="lblCaptchaMain" Visible="false" CssClass="validation-error" runat="server" />
                    </div>
                    <div class="field field-submit">
                        <asp:Button ID="btnMain" OnClick="btnMain_Click" ValidationGroup="pnlMain" Text="SUBMIT" runat="server" />
                    </div>
                </fieldset>
            </asp:Panel>

            <asp:Panel ID="pnlSecondary" Visible="false" runat="server">
                <asp:LinkButton ID="linkToMain" OnClick="linkToMain_Click" Text="Main Panel" runat="server" />
                <fieldset>
                    <div class="field field-captcha">
                        <div id="reCaptchaSecondary" class="g-recaptcha" data-sitekey="<%=reCAPTCHA_Site_key%>" data-theme="<%=reCAPTCHA_theme%>" data-size="<%=reCAPTCHA_size%>"></div>
                        <asp:Label ID="lblCaptchaSecondary" Visible="false" CssClass="validation-error" runat="server" />
                    </div>
                    <div class="field field-submit">
                        <asp:Button ID="btnSecondary" OnClick="btnSecondary_Click" ValidationGroup="pnlSecondary" Text="SUBMIT" runat="server" />
                    </div>
                </fieldset>
            </asp:Panel>

        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>

page.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Data;

/* FOR CAPTCHA VERIFY */
using System.IO;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

namespace MySite.com.section
{
    public partial class Page : System.Web.UI.Page
    {
        /* CAPTCHA */

        /* Use this in the HTML code your site serves to users. */
        public string reCAPTCHA_Site_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        public string reCAPTCHA_theme = "light";
        public string reCAPTCHA_size = "compact";

        /* Use this for communication between your site and Google. Be sure to keep it a secret. */
        private string reCAPTCHA_Secret_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

        /* verification failed message */
        private string reCaptcha_message = "Please check &quot;I'm not a robot&quot;";

        /* Initialize the captcha field by element ID for panel */
        protected void reCaptchaScript(string element)
        {
            ScriptManager.RegisterClientScriptBlock(
                this,
                typeof(Page),
                "reCaptchaSettings",
                "var reCaptchaSettings = {'element':'"   element
                      "','settings': {'sitekey':'"   reCAPTCHA_Site_key
                      "','theme':'"   reCAPTCHA_theme
                      "','size':'"   reCAPTCHA_size   "'}};",
                true
            );
            if (Page.IsPostBack)
            {
                ScriptManager.RegisterClientScriptBlock(
                    this,
                    typeof(Page),
                    "reCaptcha",
                    "reCaptchaSetUp.init(1);",
                    true
                );
            }
            else
            {
                /* This is using jQuery to make sure the element is available, could be changed to an onload event */
                ScriptManager.RegisterStartupScript(
                    this,
                    typeof(Page),
                    "OnLoad",
                    "jQuery(document).ready(function($){ reCaptchaSetUp.init(); });",
                    true
                );
            }
        }

        /* Remote call to Google to validate captcha input */
        protected bool VerifyReCaptcha()
        {
            bool reCaptcha_Verified = false;

            var requestString = string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}&remoteip={2}", reCAPTCHA_Secret_key, Request["g-recaptcha-response"], IPInfo.IpAddress());
            var request = (HttpWebRequest)WebRequest.Create(requestString);

            // Get response
            using (WebResponse reCaptchaResponse = request.GetResponse())
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(ReCaptchaResponse));
                ReCaptchaResponse gResponse = serializer.ReadObject(reCaptchaResponse.GetResponseStream()) as ReCaptchaResponse;

                if (gResponse.Success)
                {
                    reCaptcha_Verified = true;
                }
            }

            return reCaptcha_Verified;
        }

        /* Object for mapping Google's json validation response */
        [DataContract]
        public class ReCaptchaResponse
        {
            [DataMember(Name = "success")]
            public bool Success { get; set; }
            [DataMember(Name = "error-codes")]
            public List<string> ErrorCodes { get; set; }
        }

        /* END CAPTCHA */

        protected void Page_Load(object sender, EventArgs e)
        {
            /* Initialize the captcha on main panel since it is visible on page load */
            reCaptchaScript("reCaptchaMain");

            //...//
        }

        protected void linkToMain_Click(object sender, EventArgs e)
        {
            /* (re)Initialize the captcha on target panel */
            reCaptchaScript("reCaptchaMain");
            pnlMain.Visible = true;
            lblCaptchaMain.Visible = false;

            pnlSecondary.Visible = false;
            lblCaptchaecondary.Visible = false;
        }

        protected void linkToSecondary_Click(object sender, EventArgs e)
        {
            /* (re)Initialize the captcha on target panel */
            reCaptchaScript("reCaptchaSecondary");
            pnlMain.Visible = false;
            lblCaptchaMain.Visible = false;

            pnlSecondary.Visible = true;
            lblCaptchaSecondary.Visible = false;
        }

        protected void btnMain_Click(object sender, EventArgs e)
        {
            if (!VerifyReCaptcha())
            {
                reCaptchaScript("reCaptchaMain");
                lblCaptchaMain.Text = reCaptcha_message;
                lblCaptchaMain.Visible = true;
                return;
            }

            //...//
        }

        protected void btnSecondary_Click(object sender, EventArgs e)
        {
            if (!VerifyReCaptcha())
            {
                reCaptchaScript("reCaptchaSecondary");
                lblCaptchaSecondary.Text = reCaptcha_message;
                lblCaptchaSecondary.Visible = true;
                return;
            }

            //...//
        }

        //...//
    }
}

validation.js

reCaptchaSetUp = {
    reset: 0,
    attempt: 0,
    init: function(reset) {
        reset && (this.reset = reset);
        /* grecaptcha (google) often not ready on Dom ready */
        if (!window.grecaptcha && this.attempt < 10) {
            this.attempt  ;
            setTimeout(function () { reCaptchaSetUp.init(); }, 200);
        }
        else {
            if (!window.reCaptchaSettings) {
                return;
            }
            this.attempt = 0;
            if (this.reset) {
                try {
                    grecaptcha.reset();
                } catch (e) { }
            }
            try{
                grecaptcha.render(reCaptchaSettings.element, reCaptchaSettings.settings);
            } catch (e) { }
        }
    }
};
Top