Andrea James Team : Web Development Tags : Web Development jQuery MVC

Friendlier Password Validation in .NET MVC with Custom Validation

Andrea James Team : Web Development Tags : Web Development jQuery MVC

The only thing more annoying than trying to choose a password that meets arbitrary complexity rules is trying to choose a password when you don’t know why your first choice of password was rejected. When creating your .NET MVC based user registration form, you can customise the validation logic to be very specific about what gets reported back to the user to help reduce frustration.

The following example sets up both server and client side custom validation using Data Annotations by implementing the ValidationAttribute class and the IClientValidatable interface. In general, I found that the information that was easily searchable/available out on the web was good, until I tried to fully implement validation on the client side. Hopefully this will help save other developers out there a bit of time!

The Scenario

When creating the user registration and change password functionality for a recent project, we had two restrictions on password choice and complexity.

  1. The password should be at least 8 characters
  2. The password should contain at least 1non-alpha-numeric character (at least one symbol)

It would have been quite easy to just implement the model for this functionality as follows:

public class PasswordBaseModel {
     [PasswordPropertyText]
     [Required]
     [DisplayName("New Password")]
     [RegularExpression("^(?=.{8})(?=.*\W)", "Invalid password")]
     public string NewPassword { get; set; }
}

The drawback here being that you only have a single error message for all input that fails the validation. Wait, was my password too short because I’m bad at counting characters, or did I forget to include the “*” character because my shift key is dodgy?

You could always add multiple RegularExpression data annotations with different regex patterns to address each validation rule and report back different messages for each rule, and then you could pack up and go home early. No need to reinvent the wheel. But all those attribute decorations on your properties might start to get overwhelmingly clunky, or maybe you genuinely need to do something not covered by a regex (like making sure a new password isn’t a repeat of an old one). That’s where a custom validation attribute can come in.

Creating a Custom Validation Attribute

In my case I decided I just wanted to put all my validation logic into a single class for potential future reuse and to streamline my model class. So I created a PasswordValidation class that inherited from System.ComponentModel.DataAnnotations.ValidationAttribute more or less by following this tutorial to the letter:

https://msdn.microsoft.com/en-us/library/cc668224(v=vs.110).aspx

The logic of my IsValid method essentially performed the two checks in sequence. First it checked whether the password was at least 8 characters, then it checked that there was at least one symbol character in the password. If either of these checks failed, the method returned a validation result with a tailored error message stating how exactly the password didn’t meet the requirements.

protected override ValidationResult IsValid(object value, ValidationContext context) 
{
    bool validPassword = false;
    string reason = String.Empty;
    string Password = value == null ? String.Empty : value.ToString();
    if (String.IsNullOrEmpty(Password) || Password.Length < 8) 
    {
        reason = "Your new password must be at least 8 characters long. ";
    } 
    else 
    {
        Regex reSymbol = new Regex("[^a-zA-Z0-9]");
        if (!reSymbol.IsMatch(Password)) 
        {
            reason += "Your new password must contain at least 1 symbol character.";
        } 
        else 
        {
            validPassword = true;
        }
    }
    if (validPassword) 
    {
        return ValidationResult.Success;
    } 
    else
    {
        return new ValidationResult(reason);
    }
}

I then decorated my NewPassword property with my new PasswordValidation attribute, and – easy peasy – server side validation was taken care of. But if I want to catch an invalid password before the form is submitted, I’ll need to stretch my JavaScript muscles a little.

Implementing IClientValidatable

The next step was to write the code for client side validation, leveraging the JQuery Unobtrusive Validation plugin. On my PasswordValidation class, I implemented the IClientValidatable interface, which basically involves implementing a single method.

This method is quite simple, its function is to tell the client side which JavaScript function to execute during client side validation. When your model’s editor fields are rendered, the HTML elements will be decorated with custom data- attributes which provide the validation rules and details that the jQuery Unobtrusive Validation library needs.

To do this you need to choose an arbitrary name for your client side validation method, and it must be all lowercase. I set this up based on the following C# Corner article, which I found thorough.

http://www.c-sharpcorner.com/UploadFile/abhikumarvatsa/enabling-client-side-validation-on-custom-data-annotations-w/

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
{
    ModelClientValidationRule passwordRule = new ModelClientValidationRule();
    passwordRule.ErrorMessage = this.ErrorMessageString;
    passwordRule.ValidationType = "memberpasswordvalidation"; // Type name must be all lowercase! camelCaseBadHere.
    yield return passwordRule;
}

This function can also supply a static error message when validation fails. But in my case I want to determine an error message dynamically, so I will override the default error in my JavaScript.

Implementing the JavaScript Validation

So here is where I got stuck, briefly, because I struggled to find an official reference about how to extend and use the jQuery Unobtrusive Validation library. Two resources were useful: the source code in jquery.validate.unobtrusive.js itself is well-commented, as well as the following code example:

https://thewayofcode.wordpress.com/tag/custom-unobtrusive-validation/

The JavaScript implementation has two main steps. First is a simple hook to tell the Unobtrusive Validation library about your custom validation functionality through an adapter. I call the $.validator.unobtrusive.adapters.add method and supply parameters as follows (quoted from the library source code):

  • adapterName (string) - The name of the adapter to be added. This matches the name used in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
    In this example I would supply my previously set password rule ValidationType value of ‘memberpasswordvalidation’.
  • params (array) - [Optional] An array of parameter names (strings) that will be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and mmmm is the parameter name).
    Here is where I tell the library to keep track of the parameter named ‘invalidreason’ which I will use to supply a customised/dynamic error message.
  • fn (function - The function to call, which adapts the values from the HTML attributes into jQuery Validate rules and/or messages.
    This step requires understanding what information needs to be passed into the actual custom validation rule you are creating. In my example, I am only concerned with the custom parameter I’m using to store my dynamic error message value, so I will simply pass through my params array to the rule definition.

The resulting JavaScript:

$.validator.unobtrusive.adapters.add("memberpasswordvalidation", ['invalidreason'], function (options) {
    options.rules['memberpasswordvalidation'] = options.params;
});

Then you create the actual validation logic that executes when the field is validated on the client side. Fortunately I was able to get all the online reference documentation I needed for jQuery Validation here:

https://jqueryvalidation.org/jQuery.validator.addMethod/

For my custom validator function, I wrote a straightforward translation of my C# logic in JavaScript. Once you have a function that validates the field, you tell your jQuery validator about it using $.validator.addMethod like so:

$.validator.addMethod("memberpasswordvalidation",
        function (value, element, params) { // performs the actual validation
            var result = false;
            var pwd = String(value);
            if (pwd && pwd.length >= 8) { // Must be at least 8 characters long
                if (pwd.match(/[^a-zA-Z0-9]/)) { // Must have at least 1 symbol character
                    result = true;
                    params['invalidreason'] = '';
                } else {
                    params['invalidreason'] = 'Your new password must contain at least 1 symbol character.';
                }
            } else {
                params['invalidreason'] = 'Your new password must be at least 8 characters long.';
            }
            return result;
        }, 
        function (params,elem) { // returns the invalidreason param as the message
            return params['invalidreason'];
        }
);

You’ll notice that this is where the ValidationType property we set in our C# validation rules object comes into play once again (‘memberpasswordvalidation’). As you can see, I’ve also referenced my custom parameter called ‘invalidreason’ so that when I perform the validation, I also update the reason why validation fails.

To stitch it all together, I used a second function for returning the custom parameter as the result message after validation completed (see the second function passed through to the $.validator.addMethod call).

Now when I attempt to change my password, I get a customised error message with a single validator.