Adrian Grigore

ASP.NET MVC Tip #3: Client-side form validation made easy – Part 1

In ASP.NET MVC on June 21, 2009 at 13:00

Client-side form validation has become a de-facto standard for modern web applications. However, replicating server-side validation rules on the client side can be a tedious and error-prone process.

In addition, there are some validation rules which cannot be checked completely on the client side, for example because the validation depends on information stored in the server database. For those rules you need to implement remote client-side form validation.

The xVal framework is great for automatic generation of client-side validation code for some of your server-side validation rules, but it does not support remote client-side validation.

This article shows a fully generic way to implement remote client-side form validation so that

• Validation rules remain solely in your ASP.NET MVC model
• You write each validation rule just once, and only in easily testable C# code. There is no JavaScript or other client-side counterpart .
• There is no need to branch or otherwise modify xVal or jquery.validate
• All you have to do for each new remote form validation rule is to derive from the base class shown in this article.

I’ll describe how to implement this in detail. I’ve also uploaded a demo project showing how this works in action.

A brief example

Let’s assume you are implementing a website signup form. For the sake of simplicity, lets limit the form to asking for an e-mail address and a password.

Figure 1 – Example signup form

You want to implement the signup form with both client and server side validation. For the e-mail field, let’s enforce the following validation rules:

1. Email address is not missing
2. Email address looks valid
3. There is no other user with the same e-mail address in your database.

Rules 1 and 2 can easily be checked on the client side. However, rule 3 can only be done with remote validation: Your client-side validation script needs to connect to your web server and ask if the e-mail address is already taken.

In our example, the only user already in the databse shall be adrian@lobstersoft.com. As soon as someone enters this e-mail address in the form and hits tab, return, or the Create button, an error message should appear before the form has even been posted:

Figure 2 – Error messages should appear before the form has even been posted

Listing 1 shows the entire validation logic necessary for both client and server side validation:

Listing 1 – Signup form client- and server-side validation rules

using System.ComponentModel.DataAnnotations;

namespace RemoteValidation.Models
{
    public class User
    {
        [Required(ErrorMessage = "E-mail address is missing.")]
        [RegularExpression(EmailRegEx, ErrorMessage = "Invalid e-mail address.")]
        [IsNew(ErrorMessage = "Someone has already signed up with this e-mail address.")]
        public string Email { get; set; }

        [Required(ErrorMessage = "Password is missing.")]
        public string Password { get; set; }

        public class IsNewAttribute : RemotePropertyValidator
        {
            protected override bool PropertyValid(object value)
            {
                return (string)value != "adrian@lobstersoft.com";
            }
        }

        private const string EmailRegEx = @"^(([^<>()[\]\\.,;:\s@\""]+"
                                  + @"(\.[^<>()[\]\\.,;:\s@\""]+)*)|(\"".+\""))@"
                                  + @"((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
                                  + @"\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+"
                                  + @"[a-zA-Z]{2,}))$";
    }
}

The SignUp action methods should also be easy to implement since the controller does not need to know anything about our validation rules.

Listing 2 – Signup form action methods

         //
        // GET: /Users/SignUp
        public ActionResult SignUp()
        {
            return View(new User());
        }

        //
        // POST: /Users/SignUp
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult SignUp(User model)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }

            //Add User to database and start spamming daemon here

            return RedirectToAction("SignUpComplete");
        }

Lastly, here’s how the view above is implemented.

Listing 3 – Signup form view implementation

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<RemoteValidation.Models.User>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    SignUp
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>
        SignUp</h2>
    <%= Html.ValidationSummary("SignUp was unsuccessful. Please correct the errors and try again.") %>
    <% using (Html.BeginForm())
       {%>
    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="Email">
                Enter your e-mail address:</label>
            <%= Html.TextBox("Email")%>
            <%= Html.ValidationMessage("Email", "*")%>
        </p>
        <p>
            <label for="Password">
                Enter a password:</label>
            <%= Html.Password("Password")%>
            <%= Html.ValidationMessage("Password", "*")%>
        </p>
        <p>
            Hint: To see that remote validation works, try signing up as "adrian@lobstersoft.com".
        </p>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
    <% } %>

    <%= Html.ClientSideValidation<RemoteValidation.Models.User>()%>
</asp:Content>
[/sourcecode ]


Note that the View does not contain any JavaScript or other means to specify client-side validation rules. Everything is done transparently and automatically behind the scenes.


<h2>Prerequisites</h2>

In order for this to work, you need to set up a few things first:
<ol><li>
Data Annotation validation attributes for server-side validation. IMO this is the best way to handle server-side validation anyway, even if you are not using client-side validation at all.

Brad Wilson has written a great <a href="http://bradwilson.typepad.com/blog/2009/04/dataannotations-and-aspnet-mvc.html">blog article</a> on how to use DataAnnotations in ASP.NET MVC.

Note that there is a bug in DataAnnotationModelBinder which might lead to NullReferenceExceptions when using custom ViewModels. This does not become apparent in our demo project, but if you should encounter this problem, you can find a fix in <a href="http://stackoverflow.com/questions/820468/how-does-dataannotationsmodelbinder-work-with-custom-viewmodels">this StackOverflow posting</a>.
</li><li>
Download and reference <a href="http://bassistance.de/jquery-plugins/jquery-plugin-validation/">jquery.validate </a>in your Master Page.
</li><li>
Download and reference <a href="http://xval.codeplex.com/">xVal</a>  version 0.8 or later in your project. xVal is a great framework for easy implementation of client-side validation in ASP.NET MVC. It transforms standard server-side validation rules into client-side validation rules recognized by jquery.validate.

Steve Sanderson describes how to set it up and use in <a href="http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/">this blog article</a>.
</li></ol>
Once you get this far, you can implement rules 1 and 2 from our example. You could also implement rule 3, although you'd have to derive it from System.ComponentModel.DataAnnotations.ValidationAttribute, so there would't be any client-side validation for that.

<h2>Implementing generic client-side Remote Validation</h2>

While rules 1 and 2 are automagically enforced by xVal on both the client and server side, rule 3 is only checked when the user posts the form. That's because xVal does not know what to do with our custom rule. It just looks for standard validation rules like Required, StringLength or RegularExpression and ignores everything else.

Enforcing rule 3 on the client side as well without incurring any additional effort is where the technique I would like to present comes into play.

The first step is not to derive your custom validation rule from ValidationAttribute, but from the RemotePropertyValidator class I implemented. This is already depicted in Listing 1 above.

RemotePropertyValidator is in turn derived from ValidationAttribute, but it also implements xVal's ICustomRule interface. This allows it to specify a JavaScript function that should be executed in order to check if the given property is valid on the client side.

RemotePropertyValidator tells xVal to execute the JavaScript function "RemotePropertyValidation". The parameters for this function should be the type of your derived custom validator and the Error message you specified:

<strong>Listing 4 - RemotePropertyValidation class</strong>

   public abstract class RemotePropertyValidator : ValidationAttribute, ICustomRule
    {
        public CustomRule ToCustomRule()
        {
            return new CustomRule(
                &quot;RemotePropertyValidation&quot;, // JavaScript function name
                new
                    {
                        validator = ToString(),
                        errorMessage = base.ErrorMessage,
                    }, // Params for JavaScript function

                base.ErrorMessage
                );
        }
    }

You might be wondering why I am checking for empty strings / null in Listing 4. That’s because of differences between how xVal / jquery.validate work on the client side and how the DataAnnotationsModelRunner is implemented on the server side: While it is possible to implicitly implement a Required validator by deriving from ValidationAttribute on the server side, it is not possible to do this with ICustomRule descendents on the client. So I am checking for empty strings / null to avoid inconsistent behaviour.

The ClientSideRegEx property can be set to a regular expression that will be executed on the client before the remote validation is done. You can use it to avoid unnecessary calls to your RemoteValidation controller.

Now, when the user starts typing something in the e-mail field, the browser will execute the JavaScript function “RemotePropertyValidation”. Note that this function will receive your derived server-side validator’s object type and your validator’s error message as parameters.

Next, we need to implement a generic RemotePropertyValidation function. In this function we can create a “remote” validation rule as supported by jquery.validate and attach it to the Email e-mail input field’s rules collection:

Listing 5 – Generic client-side remote validation function

function RemotePropertyValidation(value, element, params) {
    var wrappedElement = $(element);
    if (wrappedElement.rules()[&quot;remote&quot;] === undefined) {
        //add optional regEx validator to minimize ajax requests
        if (params.regEx !== null &amp;&amp; wrappedElement.rules()[&quot;xVal_regex&quot;] === undefined) {
            wrappedElement.rules(&quot;add&quot;, {
                xVal_regex: [params.regEx],
                messages: {
                    xVal_regex: params.errorMessage
                }
            });
        }
        var remoteRule =
        //add a new remote validation rule
        wrappedElement.rules(&quot;add&quot;, {
            remote: {
                url: &quot;/RemoteValidation/Property&quot;,
                data: {
                    value: new CreateInputValueAccessor(wrappedElement.attr(&quot;name&quot;)),
                    validator: params.validator
                }
            },
            messages: {
                remote: params.errorMessage
            }
        });

        //validate element again to trigger the new rule(s)
        $(&quot;form&quot;).validate().element(wrappedElement);
    }
    return true;
}

function CreateInputValueAccessor(inputName) {
    return function() {
        return $(&quot;[name=&quot; + inputName + &quot;]&quot;).val();
    };
}

The RemotePropertyValidation () function should be referenced in your Master page. Now the first time a user enters something in the Email field , jquery.validate will first validate it using the Required and the Regex rule. If both rules are satisfied, it will check if the e-mail address is already taken with the validation rule that RemotePropertyValidation() inserted on the fly. This will fetch the following URL and parse the JSON reply as validation result.:

http:///RemoteValidation/Property?value=&validator=RemoteValidtion.Models.User.IsNew

Now we just need to implement a RemoteValidation that construct an appropriate validator object (note that this is provided in “validator” request parameter), let it validate the user input and return the validation result as JSON:

Listing 6 – RemoteValidation controller

using System;
using System.Reflection;
using System.Web.Mvc;
using RemoteValidation.Models;

namespace RemoteValidation.Controllers
{
    public class RemoteValidationController : Controller
    {
        //
        // GET: /RemoteValidation/Property
        public JsonResult Property()
        {
            Type validatorType = Type.GetType(Request[&quot;validator&quot;], true);
            var validator = (RemotePropertyValidator) Activator.CreateInstance(validatorType);
            return Json(validator.IsValid(Request[&quot;value&quot;]));
        }
    }
}

And that’s it! Now that you have the JavaScript RemotePropertyValidation function and the remote validation controller in place, all you need to do for new custom validation rules is to derive them from RemotePropertyValidator. This ensures that your validation rules are are automatically enforced on both the server and the client.

For example, all you’d need to implement for server AND remote client-side validation of password strength is this:

Listing 7 – Complete implementation of an additional client- and server-side Validator

 public class IsSafePasswordAttribute : RemotePropertyValidator
        {

            public IsSafePasswordAttribute()
            {
                //perform some simple password strength check with a regular expression
                //on the client side first
                ClientSideRegEx = ".{8,20}";
            }

            protected override bool PropertyValid(object value)
            {
                //Insert more elaborate server-side / remote client side password checking
                // logic and return result here...
            }
        }

Caveats

There are a few things you should keep in mind when using this technique:

  • You can’t implicitly implement a Required validator using this technique, so if a property is not optional, you must always decorate it with a Required validator apart from of your own RemotePropertyValidator descendant. It wouldn’t really make sense to implement a Required validator this way anyway. Please see the Implementation section above if you are interested in the reason for this.
  • You can only apply one remote validation rule per form field. This is a limitation of jquery.validate, and it makes sense not to have more than one remote validation rule anyway since you want to minimize the amount of server postbacks as much as possible. If you need to remotely check two different rules on the same property, you can always write a new rule which incorporates both checks, so the only problem is finding an error message that fits both validation rules.
  • This approach only works for Validation Attributes applied to properties, not to entire business entities. I’ll discuss a similar approach for validating entire business entities in the second part of this article.

Download the finished demo project

Summary

Now you know how to implement remote client-side validation without writing any custom JavaScript code. I discussed how to implement all validation rules, even those that can only be checked on the server, on both the client AND server side in C# code only. I showed how you can do this without any additional effort when implementing new rules.

The only real limitation is that the business rule can check only a single property, not an entire business entity. Stay tuned for the second part of this article, where I’ll discuss how to circumvent this limitation in a similarly easy way.

Edit: The second part of this article has already been posted here.

Advertisements
  1. Excellent work! I love how simple you’ve made the RemotePropertyValidator API.

    I’ll email you to discuss some further ideas…

  2. Really great work!

  3. Wow, spot on! Something like this should be baked into the framework!

  4. Thank you! Adrian Grigore. You gave me some idea for jQuery.

  5. ASP.NET MVC Tip #3: Client-side form validation made easy | devermind.com…

    DotNetBurner – burning hot .net content…

  6. Nice post. I couldn’t tell from the code — do the data annotations allow for any type of localization?

  7. Hi Joe,

    The data annotations support either strings or resource id’s for the error messages, so you can easily localize them.

  8. Hi Adrian,

    Looks fantastic! I guess this now bridges the gap for all possible validation types, client, server and remote client “ajax”. Hey also, thanks for taking the time to comment on my validation post and hope I helped ya somewhat.

    If yourself or anyone struggles encorporating model validation whilst using Linq to Sql see my article http://goneale.com/2009/03/04/using-metadatatype-attribute-with-aspnet-mvc-xval-validation-framework/. The title states it regards metadata type, but should have given it a better name as it really demonstrates xVal + L2S + data annotations which typically can’t be done due to L2S constantly performing code re-generation.

  9. […] devermind.com: Client-side form validation made easy (w/ xVal) […]

  10. Hi

    I just stumbled across this great post and it seems to do everything I want but I have never used xval, jquery validation and my knowledge of mvc,C# and jquery are still at the noob level so I am having some trouble following maybe you could clear some stuff up for me thanks.

    1st
    I see your using a typed view: RemoteValidation.Models.User. What happens if I want to pass some other data how would I get buy this? Do I have to make another class tore the User model and the other stuff i want?

    2nd.
    In your code you say like “//add optional regEx validator to minimize ajax requests” is this for the email address? I thought this line “[RegularExpression(EmailRegEx, ErrorMessage = “Invalid e-mail address.”)]” did that for both Client and Server Validation.

    Then you have this line

    “For example, all you’d need to implement for server AND remote client-side validation of password strength is this: ”

    public class IsSafePasswordAttribute : RemotePropertyValidator
    {

    public IsSafePasswordAttribute()
    {
    //perform some simple password strength check with a regular expression
    //on the client side first
    ClientSideRegEx = “.{8,20}”;
    }

    protected override bool PropertyValid(object value)
    {
    //Insert more elaborate server-side / remote client side password checking
    // logic and return result here…
    }
    }
    So first you have this constructor
    public IsSafePasswordAttribute()
    {
    //perform some simple password strength check with a regular expression
    //on the client side first
    ClientSideRegEx = “.{8,20}”;
    }
    So I am unclear does this only happen for client side? Like is the constructor here for client side? Or is it l used it for both(client and server) unless this is specified?
    protected override bool PropertyValid(object value)
    {
    //Insert more elaborate server-side / remote client side password checking
    // logic and return result here…
    }
    But then if this was true then this
    protected override bool PropertyValid(object value)
    {
    return (string)value != “adrian@lobstersoft.com”;
    }

    Would only validate on the server side but when running the example it is obviously doing a check on the client side.
    So I am missing something.
    I also don’t get this
    ClientSideRegEx = “.{8,20}”;
    Like I can see it is used for your range validation but how is it getting set. Is xVal using this or jquery validation using this. I am just trying to figure out what I would setup my own stuff. I am not sure if there is some sort of documentation or what.
    The property name yet confuses me again since is saying to me this is only used for client side meaning I would have to right the same code again for server side?

    The overall I don’t know what to I should be changing and what I can leave alone.
    Like if I start a new project and start doing my validation do I include these files?
    DataAnnotationsModelBinder.cs
    ExtensionMethods.cs
    RemoteValidators.cs

    Plus of course the xval files.
    Do I need to change any of these .cs files? Or can I use them as is?
    Like do I just start inheriting the “RemotePropertyValidator” and just start typing or do I have to do some other changes?

    Thanks

  11. @Chobo,

    It sounds as if you are doing your first steps with ASP.NET MVC. MVC significantly differs from the usual webforms approach, so I would definitely recommend having a look at one of the available ASP.NET MVC books. In particular, this free book chapter should help (it certainly helped me):

    http://devermind.com/aspnet-mvc/aspnet-mvc-beginners-guide

    Secondly, if you’ve only read this article, I’d also recommend downloading the demo project at the end of this article, playing a bit with it and using the debugger where you are not sure how exactly things are working.

    I’m not sure If I can help you fill all the gaps, but I’ll try to address some of your questions:

    1: I’d use a custom viewmodel for this. See this article for more details:

    http://devermind.com/linq/aspnet-mvc-using-custom-viewmodels-with-post-action-methods

    2: The regex validator mentioned in Listing 5 could also be used for remote validating the e-mail address, but in my example it is not implemented this way (the second rule shown in listing 7 is though!). You seem to be confusing client-side Javascript and server-side c# code. Javascript code in listing 5 enforces client-side validation for the regular expressions specified in RemoteProperty validation rules.

    RegularExpression rules on the other hand are automatically translated to jquery.validate client-side regex rules by XVal. You don’t need to write any javascript code (not even generic code like in listing 5) for that.

    Regarding your questions about listing 7: Again, all C# you see in this article is executed on the server side. Only listing 5 contains Javascript code, and this is executed on the client side. But this code (plus xVal of course) is bridging the gap between client and server side validation with a http request. That’s what remote client-side validation is all about. So the same PropertyValid() method is executed whenever the user types something (remote client-side valiation) and also when the user posts the form (server-side validation).

    You don’t have to repeat any validation rules, and you don’t need to write any custom code (just copy and paste what I provided here) that’s what this article is about.

    If you are starting a new project, you can use the three files you quoted as is. This is generic code that does not need to be altered. You just need to derive from RemotePropertyValidator. And don’t forget to add the javascript code (jquery, jquery.validation,listing 5) to your master page.

  12. @Adrian Grigore

    Yep, I just started looking at MVC. I been reading the free chapter and I just waiting to buy this book

    http://www.amazon.ca/ASP-NET-Framework-Unleashed-Stephen-Walther/dp/0672329980/ref=sr_1_4?ie=UTF8&s=books&qid=1246887867&sr=8-4

    Yes when writing the post I had not looked too much at the demo(seeing it was 1 in the morning lol- I probably should have waited till I had a clear head and then written the post).
    Today I got a chance to go with the debugger and it makes more sense now still confused about some of things though.

    One thing that confuses me and I wrote wrong in my previous post.

    I still don’t get why you have a constructor with this in it:

    ClientSideRegEx = “.{8,20}”;

    Why are you using it? Why not just use [RegularExpression] tag? won’t that get you the same thing?

    When I test it I can see through the debugger I see it goes to “IsSafePasswordAttribute” and sets up that property.

    So I see it sets it up for the jquery client side. Then when I start typing say 3 characters the client side validation happens. I tried using [RegularExpression] tag and it seems to work the same way.

    Another thing I noticed but I guess this is the remote validation in action. Is that when you type in the 8th character it goes to the server. How does it know to go at the 8th character to the server? If I do something else do I have to set this somewhere or does it look at the “PropertyValid” and determine when it should do a remote check?

    It is all starting to make more sense to me now that I been playing with the debugger and read the article a million times. I will continue to read it till I understand it fully(well lots of the code you used to make it I won’t understand for a long time it is too over my head right now).

    I have another question.

    How about all the tags from Jquery.Validate. There are so many like email, minlength, maxlength.

    Like I know your using “DataAnnotations” and I am guessing that somehow [Required] and gets mapped later on to Jquery.Validate [Required].

    But It would be cool to if you could use all the stuff that is in jquery.Validate I am not sure whos job that falls under if it is Xval or what or if I am not just seeing it.

    Thanks

    Thanks

  13. Very good post man. I wrote something very similar on server validation a few months back and it still gets a ton of traffic which shows how important of a topic it is. Hopefully there will be somewhat of a “standard” out there.

  14. @Chobo: About the ClientSideRegEx: You are right, a RegularExpression validator does just the same thing. I included the regex nevertheless because I often use a regular expression with my remote validators anyway and I don’t want to to have to specify the validator’s error message twice. So this is just a convenience function for keeping things DRY.

    Regarding your second question: There only is a postback to the server after the 8th character, because strings with 7 characters or less don’t match the regular expression. That’s the idea behind having a regular expression – To make the form validation more resposive and to save on server resources.

    Regarding your last question: converting server-side rules into client-side rules is precisely what xVal does. I agree it would be great to have more standard rules like email, but xVal only understands rules that are already implemented in System.ComponentModel.DataAnnotations. It also understands Castle validation rules, but I haven’t used those so far because I couldn’t even compile Castle project from source.

  15. Great post… Definitely a lack of this information online for the moment, many thanks for sharing this and the use of data annotations.
    cheers,

  16. Great post! I do have a question that I would like your thoughts on….

    Suppose you were using a Repository pattern where IUserRepository was an argument in the UsersController constructor and you were using an IOC container for TDD purposes.

    How could I replace “return (string)value != “adrian@lobstersoft.com”;” from the IsNewAttribute, so that it checks against the IUserRepository? Any thoughts on this?

    Thanks. –John

  17. Hi John,

    Thanks for your interest in my article and sorry for the slow reply.

    I am heavily using IOC in my current ASP.NET MVC project as well.

    The simplest solution would be to make all your repositories originating from the same web request share the same context. Next, create a factory class that constructs a real repository / returns the mock testing repository. Lastly use that factory class to create a repository whenever you need one (in this case in the Validation Attribute).

    HTH,

    Adrian

  18. Hi Adrian!

    This is a fantastic solution but i’m having trouble implementing it!

    I think i’ve got it mostly right. But the validator is never actually going to the server to get the result. It is ending up invalid no matter what I enter and in Firebog there is no requests showing in the Net tab.

    what I step through the javascript it does add the remote rule to the field.

    any ideas what on what could be going wrong?

  19. @Patricia: Remote validation is only executed when all other validators have returned true as validation result. This is done on purpose to save on server resources.

    So it seems like you have multiple validators on the field and one of the other validators (not the remote validation validator) always comes up as false. My guess would be that you have supplied a ClientSideRegEx to RemotePropertyValidator that never matches your input.

  20. Hi Adrian,

    Each of the validators has a different message. and the error message for the remote call is the one showing up!

  21. @Patricia: That would support my theory. Check the ClientSideRegEx property of your RemotePropertyValidator descendant.

  22. Regarding this: “This approach only works for Validation Attributes applied to properties, not to entire business entities. I’ll discuss a similar approach for validating entire business entities next week in the second part of this article.”

    Any idea when the second will be posted? E.g, assume I have a dropdown and a textbox (for integers) on the same form, and that the legal values in the textbox change based on the dropdown value and server-side information – hence, to know if the integer is valid, I need to pass the integer and the dropdown value to the server, validate it, etc. Obviously this is a class-level rule as opposed to a property level rule, but I’m not sure how to get this working via the attributes as you described. I’ve seen how I can get it to work using xVal directly, and I can do that, but I’d rather have that read from the model.

    Side note, the aforementioned dropdown is dependent on an additional dropdown, and is rendered on first page display via Html.RenderAction pointing to an action that returns a Partial View Result. The PartialViewResult either renders a placeholder text (if the associated dropdown has no selected value) or a full-blown dropdown list with values. When I use xVal like this:

    .AddRule(“Length”, new xVal.Rules.RemoteRule(Url.Action(“LengthValidation”)))

    And look at the form values, the dropdown that was initially not there is never posted in the form. If I change the code to instead always render the dropdown with a single “Choose” option, then the value posted to the form is always empty regardless of what is chosen. Finally, if the dropdown is rendered with all of the options, the current value is always sent as part of the FormCollection. Not sure if I have to do something to “register” the dropdown or not, but found it odd…

  23. Hi Glenn,

    My apologies for not posting the second part any earlier. It’s been a very busy time at working lately… I’m hoping to post it within then next 2 weeks though.

  24. Thanks Adrian, I look forward to it! FYI, after my post I realized your attached solution was different than what your post covered.. Unfortunately it didn’t work when I used it in VS 2010 Beta 2 (I know, far from surprising, but wanted you to know).

    FYI, here’s what I did to get it to compile in VS2010 Beta 2:

    1. Used the solution converter here (to upgrade from MVC to MVC2): http://weblogs.asp.net/leftslipper/archive/2009/10/19/migrating-asp-net-mvc-1-0-applications-to-asp-net-mvc-2.aspx

    2. Opened the solution in VS2010 beta 2, went thru the usual conversion; indicated I wanted to upgrade sites to ASP.NET 4.

    3. Removed the System.ComponentModel.DataAnnotations DLL from /bin

    4. Updated the reference for xVal to my local copy of 0.8 (same version as the project)

    5. ValidationAttribute.TryValidate, referenced a few times in DataAnnotationsModelBinder, is no longer in the API; I updated to use ValidationAttribute.GetValidationResult (the rest of the code was self explanatory)

    After all of this work, I was left in the same spot I was previously with VS2010 Beta 2- the remotevalidationrule is constructed on the client when the field is first asked to be validated, a response is sent to the server, the server responses, and then… nothing.. Nada. I even changed the controller’s response to simply return a JsonResult of false to bypass the logic, breakpoint shows that is happening, but nothing happens on the client. Note the other client-side rules fire just fine.

    Oh well. Thus is the price of bleeding edge technology.

  25. Aha! I incorrectly assumed that since I stepped through the process in the debugger and there was no exception, the method returned a result properly. However, when I directly accessed the validator, this is what greeted me:

    This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.

    Brand new in MVC2. Sadly I even remember reading about that (potential security vulnerability) and didn’t consider it.

    So, allow me to give you step #6 that seems to get the property validation working in VS2010 Beta 2 / MVC2:

    6. On RemoteValidationController, change the return for both Property and Entity to use the overloaded Json method that allows you to bypass the new security check, like this:

    return Json(validator.IsValid(Request[“value”]), JsonRequestBehavior.AllowGet);

  26. Thanks for the detailed upgrading list, Glen! I’m sure it will come in handy when I upgrade to ASP.NET MVC 2 🙂

  27. Regarding this: “This approach only works for Validation Attributes applied to properties, not to entire business entities. I’ll discuss a similar approach for validating entire business entities next week in the second part of this article.”

    I too am patiently waiting for the follow-up article. Please find some time to post it Adrian.

    Thanks for the brilliant work so far!

  28. Hi Adrian,

    Great post, however I also would give my right arm for the ‘validating entire business entities ‘ post !!!

    All the best.

  29. Hi Adrian,
    it is very nice piece of work.
    I’ve just encounter an issue when you get a page with multiple forms. you get an javascript error on the call of jquery.validate. To fix it I’ve change $(“form”).validate().element(wrappedElement); by $(“#” + element.form.id).validate().element(wrappedElement); . Obviously you need to id your forms.

  30. Good point, Olivier. I’ve noticed this problem when working on my current project too since I wrote the article. Note that you can also get away without using form ids:

    var validator=$(wrappedElement[0]).closest(“form”).validate();

  31. Hi Adrian,
    it is a good one too ;-). Did you manage to solve this issue: when a user change some of his information but not is email, the validation return an error because the email is already used (email value display on form = email stored in the repository). so basically if we take the assumption that the username cannot change once a user is created, any update operation could validate against it. So if a user update his profile, 2 pieces of information need to be sent over the server email + username when the email field validation occurs. So if the email value sent for uniqueness validation match the current username no error message should be triggered.

  32. @Olivier: Yes, that’s what I mean by entity-based validation. I am going to show this in the next article. I had planned to write this MUCH earlier, but lately I am very busy at work…

  33. […] my previous article about ASP.NET MVC Client-Side validation, I showed how to set up your project so that you […]

  34. Hi Adrian,

    Nice work. I tried to use your code with asp.net mvc 2. But it doesnt work coz differnent version of system.web.mvc. Is there any fix for it.

    Regards
    Parminder

  35. @Parminder: Basically it works fine with MVC2 (I’ve been using it that way for 2 months now), you just need to recompile the solution with the new system.web.mvc.dll.

  36. Hi Adrian,

    It shows problem with the extension methods (DoesAnyKeyHavePrefix,FindKeysWithPrefix
    here are the lines whre problem exists.

    if (bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey))
    var keys = bindingContext.ValueProvider.FindKeysWithPrefix(fullPropertyKey);
    if (keys != null && keys.Count() > 0)
    modelState = bindingContext.ModelState[keys.First().Key];

    I updated your project to mvc2 and then even that was not working.
    Your help will be appreciated.

    Regards
    Parminder

  37. @Parminder: You might also have to remove the model binder with from the demo project so that the default model binder from MVC 2 becomes active. If that does not work, try updating the xVal version.

  38. Hi Adrian,
    I sent you and email with the test project. The project doesnt even compile. I also updated xVal version to the latest one. I was reading the RTM doc which say.

    Changes in ASP.NET MVC 2 Beta
    The IValueProvider interface replaces all uses of IDictionary
    Every property or method argument that accepted IDictionary now accepts IValueProvider. This change affects only applications that include custom value providers or custom model binders.

    This might be the reason.
    Error 6 The type arguments for method ‘System.Linq.Enumerable.Count(System.Collections.Generic.IEnumerable)’ cannot be inferred from the usage. Try specifying the type arguments explicitly. D:\Development\SellYourOldBooks\source\SellYourOldBooksWeb\SellYourOldBooksWeb\Models\DataAnnotationsModelBinder\DataAnnotationsModelBinder.cs 73 41 SellYourOldBooksWeb

    Thanks
    Parminder

  39. @Parminder: I’m sorry, but my schedule does not permit debugging your project. The demo project provided with this article worked fine at the time I released it (namely with ASP.NET MVC which was still the standard then). I am using the same approach in my current project with ASP.NET MVC 2, so the basic principle shown here is still working. But unless you would like to hire me to help you, I’m afraid you will have to figure out the details yourself.

  40. Hi Adrian,

    Thanks a lot for your help and support. As I was working on this project just for learning and not for doing any major development and not in the situation to hire you. But definately if I need your furthur help, I will hire you.

    thanks again for the codes and the mails.

    Regards
    Parminder

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

%d bloggers like this: