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:
- Add <add verb=”GET” path=”captcha.ashx” validate=”false” type=”ManagedFusion.Web.Handlers.CaptchaImageHandler, ManagedFusion.Web.Captcha” /> to <httpHandlers> in Web.config
- 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
- 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();
}
}
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 |
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 |
Hi Noah,
The extensions you provide here are really cool!
Thanks.
Comment by Paolo Izmoto — December 16, 2008 @ 1:42 pm |
Hi Noah,
but what happen to Nick Berardi’s link!!! i can’t see his!
thanx for yr article
would u please copy link container here in your webpage?!
Comment by آتی — February 22, 2009 @ 8:21 am |
Fixed. Thanks!
Comment by noahblu — February 26, 2009 @ 9:28 pm |