jQuery Form Validation with ASP.NET

I’ve been working on refactoring my various Account area forms so that they look good on the screen. I’ll admit to using a graphic I found on Google Images – I suspect it belongs to Wizards of the Coast, so I don’t want to use it in a production environment. Fortunately, I have a friend who is a lot more artistic than I am and she is producing a background for me. Until then, the graphic is a placeholder.

One of the things I wanted to do during the refactoring is to add some client-side validation. I already have server-side validation and that is staying in there. You should never trust the input coming from the user – there will always be malicious users who will try to circumvent your controls. However, client side validation gives the user more immediate feedback since it does not involve a round trip to the server.

To do this, I’m going to lean on jQuery Validation Plugin as it does a good portion of what I want and has minimal configuration. My registration form is based on my RegisterAccountVM view-model, which has three fields – Email, Password and ConfirmPassword. I want the email address to be required and a valid email address, the password to be between 6 and 128 characters and meet complexity requirements; finally, the confirm password must equal the password. I can handle all the configuration except for the complex password using the jQuery Validation Plugin standard configuration, like this:

    $("#Account form").validate({
        rules: {
            Email: {
                required: true,
                email: true
            },
            Password: {
                required: true,
                minlength: 6,
                maxlength: 128,
                complexPassword: true
            },
            ConfirmPassword: {
                required: true,
                minlength: 6,
                maxlength: 128,
                equalTo: "#regPasswordField"
            }
        }
    });

Note that the keys in the rules object are the name field of the input which, in ASP.NET MVC, are also the name of the fields in the view model.

The rule for complexPassword I’ve listed in the Password rules is non-standard. I need a custom validator to handle the complexity. My requirements for this are that the password must contain one character from each character group – upper case, lower case, numeric and symbols. To do this, I use a recipe from the documentation:

    jQuery.validator.addMethod("complexPassword", function(value, element) {
        // Min to Max length is already handled - just have to handle complexity
        var hasUpper = false, hasLower = false, hasNumeric = false, hasSymbol = false;

        for (var i = 0 ; i < value.length ; i++) {
            var ch = value.charAt(i);
            if ("ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(ch) !== -1)
                hasUpper = true;
            if ("abcdefghijklmnopqrstuvwxyz".indexOf(ch) !== -1)
                hasLower = true;
            if ("0123456789".indexOf(ch) !== -1)
                hasNumeric = true;
            if ("!@@#$%^&*()_-+=|\}{[]:;''?/.,".indexOf(ch) !== -1)
                hasSymbol = true;
        }
        return (hasUpper && hasLower && hasNumeric && hasSymbol);
    }, "Password must be more complex");

My Areas/Main/Views/Layout.cshtml file contains a section for the scripts, defined like this:

    <!-- BootStrap Javascript Dependencies -->
    <script src="~/jspm_packages/github/components/jquery@2.1.3/jquery.min.js"></script>
    <script src="~/jspm_packages/github/twbs/bootstrap@3.3.4/js/bootstrap.min.js"></script>

    <!-- JSPM Boot Loader -->
    <script src="~/jspm_packages/system.js"></script>
    <script src="~/config.js"></script>

    <!-- Page Scripts -->
    @RenderSection("scripts", required: false)
</body>
</html>

The RenderSection call is used to insert the scripts section from my view. That means I need to add the following to the bottom of my Areas/Account/Views/RegisterAccount/Index.cshtml file:

@section scripts {
<script src="~/jspm_packages/github/jzaefferer/jquery-validation@1.13.1/dist/jquery.validate.min.js"></script>
<script>
    // Add a custom rule to jquery validation
    jQuery.validator.addMethod("complexPassword", function(value, element) {
        // Min to Max length is already handled - just have to handle complexity
        var hasUpper = false, hasLower = false, hasNumeric = false, hasSymbol = false;

        for (var i = 0 ; i < value.length ; i++) {
            var ch = value.charAt(i);
            if ("ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(ch) !== -1)
                hasUpper = true;
            if ("abcdefghijklmnopqrstuvwxyz".indexOf(ch) !== -1)
                hasLower = true;
            if ("0123456789".indexOf(ch) !== -1)
                hasNumeric = true;
            if ("!@@#\$\%^&*()_-+=|\\}{[]:;\"'<>?/.,".indexOf(ch) !== -1)
                hasSymbol = true;
        }
        return (hasUpper && hasLower && hasNumeric && hasSymbol);
    }, "Password must be more complex");

    $("#Account form").validate({
        rules: {
            Email: {
                required: true,
                email: true
            },
            Password: {
                required: true,
                minlength: 6,
                maxlength: 128,
                complexPassword: true
            },
            ConfirmPassword: {
                required: true,
                minlength: 6,
                maxlength: 128,
                equalTo: "#regPasswordField"
            }
        }
    });
</script>
}

I’ve done some other work in the refactoring, including changing the main.less to have an Account.less inclusion, rather than using the login.less separate file. I’ve also refactored all the Account views to handle my new format. Finally, I’ve updated the form in the ForgotPassword workflow to have the same sort of validation as the account registration. I’ve also moved the complexPassword definition into its own Javascript file so that the same code can be reused in both the ForgotPassword and RegisterAccount views. I also suspect that I will want to use it in some sort of profile page in the future. Finally, I adjusted the Gulp/javascript.js file to account for the jQuery global so I could use eslint on the new file.

One other thing to note. I had a hell of a time with Visual Studio 2015 CTP 6 today. It decided it wanted to hang on processing Javascript and Less files constantly. As a result of this, I switched my editor (there is only so much frustration one can take) and used gulp build followed by k web to run the web site. I didn’t actually use Visual Studio much today at all. Hopefully, the next build of Visual Studio will be released at BUILD at the end of the month (just one week away) and I can try that out instead.

You can check out the code at tag cs-0.0.8.