09 Mar 2008

ASP.NET MVC Preview 2 CAPTCHA using ActionFilterAttribute

42 Comments Uncategorized

My last article on ASP.NET MVC CAPTCHA was very well received by many of my readers and it even caught the eye of the DotNetKicks crowd. Now that MVC Preview 2 was released last week, many new features make encapsulating my CAPTCHA control even easier. Most notably is the ActionFilterAttribute which allows you to override the Pre and Post action events for any action the attribute is applied to.

Basically everything works the same as it did in the previous article. I just modified things for MVC Preview 2. To validate the CAPTCHA you add the attribute CaptchaValidation to the action.

[CaptchaValidation("captcha")]
public void Register(string userName, string password, string email, string question, string answer, bool captchaValid){
    // do stuff
}

You still need to register the CAPTCHA image handler.

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

I added an extension to HtmlHelper that generates a text box with autocomplete=”off”.

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

Which generates the following.

Example of CAPTCHA

You can view the source code for this on my Google Code Project, everything is available through SVN.

  1. CaptchaValidationAttribute.cs
  2. CaptchaHelper.cs
  3. CaptchaImage.cs
  4. CaptchaImageHandler.cs

Or you can download the project for you own personal use.

Tags: , , , , ,
written by
Nick Berardi
subscribe
If you found this post valuable and would like to see more like it you can follow me.

42 Responses to “ASP.NET MVC Preview 2 CAPTCHA using ActionFilterAttribute”

  1. Reply Ted says:

    Thanks
    I tried it but it is not working for me
    I am newbie for MVC
    It has been nice to get a full solution of the implementation
    Ted

  2. Reply ziros says:

    Hello, seems like nice stuff.
    any sample webpage of how to use the code ?
    TIA

  3. Reply kkl says:

    Thanks very much for your codes. However, I’ve run into some trouble using it. Would you be able to give it a quick look and see what’s wrong?

    This is what i have in the .aspx file:

    Login Name:
    Enter Below

    The codes in controller:
    [CaptchaValidation("captcha")]
    public void Register(string userName, bool captchaValid)
    {
    if ( captchaValid)
    ViewData["Name"] = userName;
    else
    ViewData["Name"] = “Invalid”;

    RenderView(“About”);
    }
    }

    The error messages seem to suggest that the parameter “captchaValid” is not in the action parameter. I have inserted a breakpoint at the start of the “Register” Action, but the breakpoint is never triggered. I’ve also tried a simple “LogActionFilter” as demonstrated in the ASP .NET MVC video and it worked fine.

    I’ve been stuck for days already and run out of ideas on what to do next. Would you be able to see what’s wrong? Thanks very much for your help.

    Error Message:
    Server Error in ‘/’ Application.
    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.
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.InvalidOperationException: 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.

    Source Error:

    An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

    Stack Trace:

    [InvalidOperationException: 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.]
    System.Web.Mvc.Controller.InvokeActionMethod(MethodInfo methodInfo, RouteValueDictionary values) +1385
    System.Web.Mvc.Controller.InvokeAction(String actionName, RouteValueDictionary values) +538
    System.Web.Mvc.Controller.InvokeAction(String actionName) +49
    System.Web.Mvc.Controller.Execute(ControllerContext controllerContext) +173
    System.Web.Mvc.Controller.System.Web.Mvc.IController.Execute(ControllerContext controllerContext) +28
    System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) +366
    System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) +55
    System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) +28
    System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +358
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +64

  4. Reply Nick Berardi says:

    Hi kkl,

    In Preview 2 they actually broke the RouteData insertion. I didn’t realize this until after the release of this post. To get the captchaValid parameter, remove it from the method and call it this way in the first line of your action.

    bool captchaValid = (bool)RouteData.Values["captchaValid"];

  5. Reply Venkat says:

    Hi ,

    I have done similar CAPTCHA image using MVC Action result.

  6. Reply kkl says:

    It’s working very smooth now. Thanks. Much appreciated.

  7. Reply Alex says:

    Hello, I have tried with the suggested implementation butfound that the captcha couldn’t be shown.

    They I try to copy the link from the captcha as follows
    http://localhost:1437/Home/captcha.ashx?guid=b344ea4ffc9e4f4bae22870af3a3647d

    and try to open it and follow errors occurred.

    Server Error in ‘/’ Application.
    ——————————————————————————–

    A public action method named ‘captcha.ashx’ could not be found on the controller.
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.InvalidOperationException: A public action method named ‘captcha.ashx’ could not be found on the controller.

    Source Error:

    An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

    Stack Trace:

    [InvalidOperationException: A public action method named 'captcha.ashx' could not be found on the controller.]
    System.Web.Mvc.Controller.HandleUnknownAction(String actionName) +133
    System.Web.Mvc.Controller.Execute(ControllerContext controllerContext) +219
    System.Web.Mvc.Controller.System.Web.Mvc.IController.Execute(ControllerContext controllerContext) +36
    System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) +419
    System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) +71
    System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) +36
    System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75

    Should I config something on the routing or anything I missed? Thanks.

  8. Reply Nick Berardi says:

    You are using Preview 3 which changed the route handler around. “captcha.ashx” in PR 2 would be handled by the handler, however in PR 3 it is handled as an action. To get around this you need to do the following for your Route:

    Constraints = new RouteValueDictionary { { “controller”, “[^\\.]*” }, { “action”, “[^\\.]*” } }

  9. Reply Alex says:

    Thanks but I checked and it is using Preview 2 only. It seems it coudln’t call the ashx.

  10. Reply viet_bui says:

    I have tried it. But it has a error:
    Configuration Error:

    Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

    Parser Error Message: Could not load file or assembly ‘ManagedFusion, Version=1.0.0.0, Culture=neutral’ or one of its dependencies. The system cannot find the file specified.

    Source Error:

    Line 105:
    Line 106:
    Line 107:
    Line 108:

    Source File: D:\MyProject\projects\mvc.psp.gate.vn\mvc.psp.gate.vn\web.config Line: 107

    Assembly Load Trace: The following information can be helpful to determine why the assembly ‘ManagedFusion, Version=1.0.0.0, Culture=neutral’ could not be loaded.

    === Pre-bind state information ===
    LOG: User = RND-VIETBL\Administrator
    LOG: DisplayName = ManagedFusion, Version=1.0.0.0, Culture=neutral
    (Partial)
    LOG: Appbase = file:///D:/MyProject/projects/mvc.psp.gate.vn/mvc.psp.gate.vn/
    LOG: Initial PrivatePath = D:\MyProject\projects\mvc.psp.gate.vn\mvc.psp.gate.vn\bin
    Calling assembly : (Unknown).
    ===
    LOG: This bind starts in default load context.
    LOG: Using application configuration file: D:\MyProject\projects\mvc.psp.gate.vn\mvc.psp.gate.vn\web.config
    LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
    LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
    LOG: The same bind was seen before, and was failed with hr = 0×80070002.

    What’s happened? Please help!
    Thanks Nick Berardi

  11. Reply la ka says:

    A report error:

    add verb=”GET” path=”captcha.ashx” validate=”false” type=”ManagedFusion.Web.Handlers.CaptchaImageHandler, ManagedFusion”

    It couldn’t load file or assembly ManagedFusion.
    Please help me!
    Thanks.

  12. Reply Alex says:

    Thanks, I found out the problem.

    Under Web.Config

    It should be ManagedFusion.Web.Mvc.Handlers.CaptchaImageHandler and works fine now. Thanks.

  13. Reply craig says:

    Hello!!!!
    I am using MVC preview 3….
    In my project I followed all the steps mention above….
    but it seems that captcha.ashx is not get called.what changes should be done related to Routing in MVC 3.
    plz help!!!!!!!
    thanks in advance….

  14. Reply Peter Andrews says:

    Hi Nick.. Nice post.. I have got your CAPTCHA working in my Preview 2. Recently I upgraded to Preview 3. The solution compiles and executes fluently but the CAPTCHA image is not displayed onto the page. What changes do I have to make in the routing scenario for page requests to captcha.ashx …. ?I am getting frustrated… Can you please upgrade your post for Preview 3 please….

    Thanks in advance

  15. Reply Nick Berardi says:

    Hi Peter,

    Add this to your Constraints:
    Constraints = new RouteValueDictionary { { “action”, “[^\\.]*” } }

    This will tell the Routes to ignore anything with a period in it for an action.

  16. Reply Peter Andrews says:

    Hi Nick….Thanks for ur Reply…..
    Now captcha images are displaying on my page….In aspx my code is

    Enter Below

    but after entering captcha image text in captcha textbox and clicking on submit button.it shows me below error…..and action method is also not called…

    The HTTP verb POST used to access path ‘/Home/About’ is not allowed.

    in web.config file code is..

    Plz tell me where is the fault…

    Thanks in Advance..

  17. Reply Nick Berardi says:

    Hi Peter,

    That seems to be an implementation problem on your end. It is basically saying you are not allowed to post to /home/about, I don’t know the reason for this, but if you are the same guy that e-mailed me. I don’t really know if you want to post your registration information to an about page, it seems like an error.

  18. Reply Satish says:

    Hi Nick.

    I am implementing your captcha into my Preview 3 solution for MVC.

    I have route initialisation code in Globax.asax. Added the ManagedFusion captcha dll to the solution .Then I have a handler registered in web.config.In the HomeController I have the action ‘Valid’.
    In a demo solution I have placed the captcha code onto Index.aspx and About.aspx views both. And Index.aspx is rendered by default.

    When I execute the solution the captcha renders superb on the default rendered Index.aspx page. Now when I redirect the page to About.aspx or any other page in the solution which has the captcha code in it, the captcha is not visible there.

    The only difference I could figure out is that , the MVC captcha works only on that page which is rendered by default(In my case it is Index.aspx). The image source URL in this case is like http://localhost:52431/captcha.ashx?guid=1464bb46f6964b5083eb82db0a3b1620

    Whereas the image source url on all other pages than the page rendered by default is
    http://localhost:52431/YourControllername/captcha.ashx?guid=1464bb46f6964b5083eb82db0a3b1620

    Can I post this as a bug in the MVC captcha?
    I can send you my demo solution if you reply to my mail.
    Thanks in advance..

  19. Reply Nick Berardi says:

    Hi Satish,

    This is my own code, so no need to post a bug anywhere you are already talking to the developer. Also can you send me the code where you have duplicated this, because I have not seen it on any of the projects in which I use this CAPTCHA.

    You have to make sure to generate the Image using the supplied code, because it automatically creates a GUID, that is only available for a couple of minutes.

    Nick

  20. Reply Selto says:

    Maybe it would be better to customize some parameters like captcha background etc.
    It would be easier for users not to hardcode, for example CaptchaImage.cs, line 388:

    gr.Clear(Color.FromArgb(255,235,235,235));

  21. Reply John says:

    Hello, I have tried with the suggested implementation but found that the captcha couldn’t be shown.

    I try to copy the link from the captcha as follows
    http://localhost:6437/Home/captcha.ashx?guid=b344ea4ffc9e4f4bae22870af3a3647d

    It shows image only when my captcha image url is as follows…
    http://localhost:6437/captcha.ashx?guid=b344ea4ffc9e4f4bae22870af3a3647d

    This is my global.ascx
    routes.MapRoute(
    “Default”,
    “{controller}/{action}/{id}”,
    new { controller = “Home”, action = “Index”, id = “” },
    new { controller = @”[^\.]*” });
    why is it so??
    any help…..

  22. Reply Nick Berardi says:

    That is because there is no directory called home. Is my guess.

    • Reply ian says:

      hi ..

      i can run this successfully in visual studio with F5,
      when I port it into IIS7, then the image is not showing, do you have any idea on this ?

      Thanks.

  23. Reply Noah says:

    I just want to clarify how you are licensing this (or what you mean by “…Or you can download the project for you own /personal/ use.”). I’m interested in modifying this source and using it in a client’s for-profit website. Are you ok with that?

    Noah

  24. Reply Fabio says:

    Do you have an example to make this work with release candidate ASPNET MVC 1.0. I have been trying to make this work but the httphandler never gets called I tried the following and image never appears.
    routes.MapRoute(
    “Default”,
    “{controller}/{action}/{id}”,
    new { controller = “Home”, action = “Index”, id = “” },
    new { controller = @”[^\.]*” });

    Thanks,

  25. Reply varlo says:

    In my AccountController Register action
    bool captchaValid = (bool)RouteData.Values["captchaValid"] always return null, nut show the image.
    And it never calls OnCaptchaValidation because protected override bool OnPreAction because System.Web.MVC.Controller doesn’t have OnPreAction method.
    How could I get captchaValid value in the case?

  26. Reply dilip says:

    protected override bool OnPreAction because System.Web.MVC.Controller doesn’t have OnPreAction method.plz help me sir

  27. Reply Hai Say says:

    hi!! i use .net framework 3.5, mvc 2.0, System.Web.Mvc, Version=1.0.0.0 . when i test link ( http://localhost:6437/captcha.ashx?guid=b344ea4ffc9e4f4bae22870af3a3647d) in my project.error
    Could not load type ‘ManagedFusion.Web.Mvc.Handlers.CaptchaImageHandler’ from assembly ‘ManagedFusion’.
    hepl me!! thanks

  28. Reply Aviv says:

    How would one set this up for an Ajax form? I’ve stated the ID for the form, but I can’t seem to grab the value for captchaValid.

    I’ve also tried:
    bool captchaValid = (bool)RouteData.Values["captchaValid"];

  29. Reply Parmjeet kumar says:

    its osem thanks…you done a good Job thanks once again..

  30. Reply Parmjeet kumar says:

    http handler was not working to solve that i use a aspx page to handle requests for image

    and nice profile picture ahaha :-)

  31. Reply fdfdf says:

    if this is how you attract people to this site …then you must be fucked up in the head!
    motherfucker why don’t you fucking post the full working project solution so people can just open and F5 it to see how it works ….your fucking way of putting half of the code as text and half in not compiling or working solution is bullshit!

  32. Reply bbqchickenrobot says:

    Thanks for the samples Nick!! Will try and port to MVC 3… if I get it working I will post back here. Also, for those of you who have a problem with this work you should probably keep your mouths shut as you didn’t pay him for his work and he offered it free for educational purposes. I think it’s hilarious when a developer can’t figure out what to do with OSS and then their frustration turns into anger. lol

  33. Reply Layinka says:

    If you are interested in using this in MVC3, you just need to make a couple of changes to the code.
    First of you need to add an ignore route to your global.asax file
    routes.IgnoreRoute(“{controller}/captcha.ashx”);
    routes.IgnoreRoute(“{action}/captcha.ashx”);
    routes.IgnoreRoute(“{controller}/{action}/captcha.ashx”);
    dont know why i had to add the 3,b4 i could get it to work
    Then add an httphandler to your web.config file

    then lastly you have to go into the CapthchaValidatingAttribute.
    change the FilterExecutingContext method param to ActionExecutingContext
    then change every
    filterContext.RouteData.Values.Add(“captchaValid”, false); to
    filterContext.ActionParameters["captchaValid"] = false; or to true as expected

    and voila it should work
    have fun trying it

    i am currently trying to work on changing it so i can use it with ajax,so pple can refresh it

Leave a Reply