Noah Blumenthal's Blog

October 28, 2008

ASP.NET MVC Captcha

Filed under: ASP.NET MVC — noahblu @ 4:56 pm
Tags: , ,

I was looking for an ASP.NET MVC Captcha control and stumbled upon Nick Berardi’s (http://www.coderjournal.com/2008/06/mvc-captcha-for-preview-release-3/).

First of all I’m using IIS7 and had trouble getting the HttpHandler to register properly.  I ended up with the following steps to get it to work:

  1. Add <add verb=”GET” path=”captcha.ashx” validate=”false” type=”ManagedFusion.Web.Handlers.CaptchaImageHandler, ManagedFusion.Web.Captcha” /> to <httpHandlers> in Web.config
  2. Add <add name=”CaptchaImageHandler” verb=”GET” path=”captcha.ashx” type=”ManagedFusion.Web.Handlers.CaptchaImageHandler, ManagedFusion.Web.Captcha” /> to the <handlers> section within <system.webserver> in Web.config
  3. Add routes.IgnoreRoute(“{handler}.ashx”); to Global.asax

So that got it working, but there were a few pieces of functionality I felt were missing:

1) I wanted the ability to style the CaptchaTextBox

The site I’m working with is pretty design intensive and I needed a way to inject CSS information into the CaptchaTextBox Html Helper.  I reworked the CaptchaHelper and modified the CaptchaTextBox as well as added some overloads:

        public static string CaptchaTextBox(this HtmlHelper helper, string name)
        {
            return helper.CaptchaTextBox(name, null);
        }

        public static string CaptchaTextBox(this HtmlHelper helper, string name, Object htmlAttributes)
        {
            return helper.CaptchaTextBox(name, ((IDictionary<string, object>)new RouteValueDictionary(htmlAttributes)));
        }

        public static string CaptchaTextBox(this HtmlHelper helper, string name, IDictionary<String, Object> htmlAttributes)
        {
            ModelState state;

            TagBuilder builder = new TagBuilder("input");
            builder.MergeAttributes<string, object>(htmlAttributes);
            builder.MergeAttribute("type", "text");
            builder.MergeAttribute("name", name);
            builder.MergeAttribute("id", name);
            builder.MergeAttribute("value", "");
            builder.MergeAttribute("maxlength", ManagedFusion.Web.Controls.CaptchaImage.TextLength.ToString());
            builder.MergeAttribute("autocomplete", "off");

            if (helper.ViewData.ModelState.TryGetValue(name, out state) && (state.Errors.Count > 0))
            {
                builder.AddCssClass("input-validation-error");
            }

            return builder.ToString(TagRenderMode.SelfClosing);
        }

I got the TagBuilder idea from checking out the Reflector on System.Web.MVC.  Pretty cool stuff there.  So now I can use the CaptchaTextBox like so:

<%= Html.CaptchaTextBox(“captcha”, new { @class = “field” })%>

2) I wanted the CaptchaValidationAttribute to invalidate my Model if the captcha isn’t valid

(instead of inject a captchaValid with a value of false into my routedata which is what it does off the shelf)

For this I modified the CaptchaValidationAttribute class.  The first thing I did was make add an ErrorMessage string property.  Then I modified the OnActionExecutingContext method to look like this:

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // get the guid from the post back
            string guid = filterContext.HttpContext.Request.Form["captcha-guid"];

            // check for the guid because it is required from the rest of the opperation
            if (String.IsNullOrEmpty(guid))
            {
                filterContext.Controller.ViewData.ModelState.AddModelError(Field, ErrorMessage);
                return;
            }

            // get values
            CaptchaImage image = CaptchaImage.GetCachedCaptcha(guid);
            string actualValue = filterContext.HttpContext.Request.Form[Field];
            string expectedValue = image == null ? String.Empty : image.Text;

            // removes the captch from cache so it cannot be used again
            filterContext.HttpContext.Cache.Remove(guid);

            // validate the captch
            if (String.IsNullOrEmpty(actualValue) || String.IsNullOrEmpty(expectedValue) || !String.Equals(actualValue, expectedValue, StringComparison.OrdinalIgnoreCase))
            {
                filterContext.Controller.ViewData.ModelState.AddModelError(Field, ErrorMessage);
                return;
            }
        }

Now I can use the CaptchaValidationAttribute like this:

[CaptchaValidationAttribute()]
public ActionResult Register(FormCollection form)
        {
// INCREDIBLY OVER-SIMPLIFIED BUT YOU GET THE IDEA
            if (!ViewData.ModelState.IsValid)
            {
                return View();
            }
        }
About these ads

5 Comments »

  1. Hi Noah,

    I’m trying this captcha module into my ASP.NET MVC application, but I can’t get it to work. I think it has to do with the beta release of MVC. I get the error CaptchaImage is not a member of System.Web.Mvc.HtmlHelper.

    Did you modify the distributed (preview3) binary from Nick Berardi? If so can you post the updated binary? If not did you change anything else?

    Thanks in advance

    Comment by JoostS — November 17, 2008 @ 11:07 am | Reply

  2. JoostS —

    I’m currently using this with the beta release without problem. Other than what I posted I don’t think I modified anything. Are you sure you’re referencing ManagedFusion.Web.Captcha?

    Noah

    Comment by noahblu — November 17, 2008 @ 1:55 pm | Reply

  3. Hi Noah,

    The extensions you provide here are really cool!

    Thanks.

    Comment by Paolo Izmoto — December 16, 2008 @ 1:42 pm | Reply

  4. Hi Noah,
    thanx for yr article :) but what happen to Nick Berardi’s link!!! i can’t see his!
    would u please copy link container here in your webpage?!

    Comment by آتی — February 22, 2009 @ 8:21 am | Reply

    • Fixed. Thanks!

      Comment by noahblu — February 26, 2009 @ 9:28 pm | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Rubric Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: