June 24th, 2008

MVC CAPTCHA for Preview Release 3

Since my last release of the MVC toolkit some major changes have taken place in the MVC Framework. I am going to do a quick run through of how they changed the MVC CAPTCHA for the better.

Originally in MVC Preview Release 1 for the MVC CAPTCHA many of you remember that the indicator for a valid CAPTCHA was passed through the parameters of the action method like so:

[ControllerAction]
[CaptchaValidation("captcha")]
public void Register(bool captchaValid, string otherParameters)
{
    // do stuff
}

However when Preview Release 2 came out the ability to pass the parameter through the action method was broken. So I had to create a hack around this:

[CaptchaValidation("captcha")]
public void Register(string otherParameters)
{
    bool captchaValid = (bool)RouteData.Values["captchaValid"];
    // do stuff
}

Apparently without realizing it in Preview Release 1, I had discovered a major feature that everybody that I explained it to saw great potential in. So I submitted a feature request and waited for the ASP.NET Team to get back to me. With the release of Preview Release 3, they finally answered my prayers and added the parameter injection feature back in to the framework.

So now this code works again in the Preview Release 3 version of the MVC CAPTCHA control.

[CaptchaValidation("captcha")]
public void Register(bool captchaValid, string otherParameters)
{
    // do stuff
}

This works because of a new property called ActionParameterson the ActionExecutingContext. It can be used to test and change any of the action methods parameters before the action method has been executed. For the purpose of the MVC CAPTCHA control it allows me to inject a true or false value in to a parameter called captchaValid, so that the action method knows that the CAPTCHA validation passed or failed.

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
	// make sure no values are getting sent in from the outside
	if (filterContext.ActionParameters.ContainsKey("captchaValid"))
		filterContext.ActionParameters["captchaValid"] = null;

	// 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.RouteData.Values.Add("captchaValid", false);
		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
	filterContext.ActionParameters["captchaValid"] =
		!String.IsNullOrEmpty(actualValue)
		&& !String.IsNullOrEmpty(expectedValue)
		&& String.Equals(actualValue, expectedValue, StringComparison.OrdinalIgnoreCase);
}

Notice in the code above all the filterContext.ActionParameters references, that is the CAPTCHA validation checking for the parameter in the method parameters list and adding the value of the CATPCHA validation to the list. Note that in order for this to work you must already have the captchaValid attribute present in your method, these actions merely fill in the value of the captchaValid placeholder.

For anybody who hasn’t used my MVC CAPTCHA control before, you only need to do two things:

1. You need to register the CAPTCHA image handler.

<httpHandlers>
    <add verb="GET" path="captcha.ashx" validate="false" type="ManagedFusion.Web.Handlers.CaptchaImageHandler, ManagedFusion" />
</httpHandlers>

2. Add the following to the View that you want the CAPTCHA to show in. Note the extension, CaptchaTextBox in HtmlHelper, generates a text box with autocomplete=”off” so that the CAPTCHA box will not have an auto-complete show up.

<label for="captcha">Enter <%= Html.CaptchaImage(50, 180) %> Below</label><br />
<%= Html.CaptchaTextBox("captcha") %>

Which generates the following.

Example of CAPTCHA

If you would like to download the latest copy of the MVC CAPTCHA it is available in my MVC Toolkit.

Download: Coder Journal MVC Toolkit
Source: Coder Journal MVC Toolkit

Tags: , ,

Social: kick it on DotNetKicks.com | Bookmark

This entry was posted on Tuesday, June 24th, 2008 at 7:08 am and is filed under ASP.NET, C#, How To. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

14 Responses to “MVC CAPTCHA for Preview Release 3”

  1. DotNetKicks.com Says:

    MVC CAPTCHA for Preview Release 3…

    You’ve been kicked (a good thing) - Trackback from DotNetKicks.com…

  2. ASP.NET MVC Blogs Says:

    [...] MVC CAPTCHA for Preview Release 3 (6/24/2008)Tuesday, June 24, 2008 from http://www.coderjournal.comSince my last release of the MVC toolkit some major changes have taken place in the MVC Framework. I am going to do a quick run through of how they changed the MVC CAPTCHA for the better. Originally in MVC Preview Release 1 for the MVC CAPTCHA many of you remember that the indicator for a valid CAPTCHA was passed through the parameters of the action method like so: [ControllerAction] [CaptchaValidation("captcha")] public void Register(bool captchaValid, string otherParameters) { // do stuff } [...]

  3. Reflective Perspective - Chris Alcock » The Morning Brew #122 Says:

    [...] MVC CAPTCHA for Preview Release 3 - Nick Berardi relooks at the captcha implementation in his MVC Toolkit with regard to changes in the MVC framework in PR3 [...]

  4. ASP.NET MVC CAPTCHA - Nick Berardi’s Coder Journal Says:

    [...] Most recent update for MVC Release Candidate 3 is [...]

  5. Dan Swatik Says:

    Nick do you have a working web site with this?

    I can not seem to make it work… I’m not sure if this is because I am using the MVC Membership Starter Kit or what…

    But it doesn’t seem to want to spit out the image instead I get a error from the MVC assembly stating that it can’t find the controller for captcha.ashx

    Please help..thanks

  6. Nick Berardi Says:

    That is because you action is probably picking it up. put a constraint on your action and controller. to check for periods. “[^\\.]*” works really well.

  7. Dan Swatik Says:

    Thanks Nick
    I actually did get it to work …well at least to display

    now I get this
    A value is required for parameter ‘captchaValid’ in action ‘Register’. The parameter either has no value or its value could not be converted. To make a parameter optional its type should either be a reference type or a Nullable type.

    I gather it has something to do with the OnActionExecuting filter thingy… where in tarnation do I place that code in my project?

  8. Dan Swatik Says:

    Actually got it working
    You have to declare the captchaValid as a nullable parameter like so

    [CaptchaValidation("captcha")]
    public void Register(bool? captchaValid, string otherParameters)
    {
    // do stuff
    }

    also in the web config make sure to declare it like this
    Not the dot Mvc

    whats listed in the blog post must be dated.. and was changed at some point.

  9. Dan Swatik Says:

    hmm either I forgot or it got cut off

  10. Bookmarks about Captcha Says:

    [...] - bookmarked by 2 members originally found by emosk8 on 2008-08-07 MVC CAPTCHA for Preview Release 3 http://www.coderjournal.com/2008/06/mvc-captcha-for-preview-release-3/ - bookmarked by 3 members [...]

  11. Noah Says:

    Thanks for the great work, this is very helpful. I recently used this and made some modifications you might find useful including:

    1) Modifying CaptchaTextBox to allow for custom html attributes (such as defining the CSS class)
    2) Modifying CaptchaValidationAttribute to automatically invalidate my model (instead of set a captchaValid value)

    Details are at http://noahblu.wordpress.com/2008/10/28/aspnet-mvc-captcha/

    Noah

  12. JoostS Says:

    Hi,

    I’m trying this captcha module into my ASP.NET MVC (beta) 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.

    Do I need to modify anything?

    Thanks in advance

  13. JoostS Says:

    Nick,

    Thanks for your reply in your mail, it’s working now. I had some problems with implementing it in vb.net.

  14. Chris Rock Says:

    I’m trying to use IIS 5.1 (XP) and 6.0 (so I’m using the .mvc extension for my controllers) but I can’t get the captch image to display. The exception generated is:
    System.Web.HttpException: The incoming request does not match any route.
    at System.Web.Routing.UrlRoutingHandler.ProcessRequest(HttpContextBase httpContext)
    at System.Web.Routing.UrlRoutingHandler.ProcessRequest(HttpContext httpContext)
    at System.Web.Routing.UrlRoutingHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext context)
    at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
    at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

    This is my route table setup:
    // For IIS 5.1 (XP)
    routes.MapRoute(
    “Default2″, // Route name
    “{controller}.mvc/{action}/{id}”, // URL with parameters
    new { controller = “Home”, action = “Home”, id = “” }, // Parameter defaults
    new { action = “[^\\.]*” }
    );

    routes.MapRoute(
    “Default”, // Route name
    “{controller}/{action}/{id}”, // URL with parameters
    new { controller = “Home”, action = “Home”, id = “” }, // Parameter defaults
    new { action = “[^\\.]*” }
    );

    The request generated is this (e.g.):
    http://localhost/Member.mvc/captcha.ashx?guid=adf8d220cedd441daf55a5c0c688dfc4

    This works great when I run it through the VS.Net 2008 web server, but not IIS 5.1/6. What am I missing?

    Thanks,
    Chris

Leave a Reply