Model validation in ASP .NET MVC

form-validation

I worked for several years as an ASP .NET MVC developer and I still do even if I do less front-end development at the moment. During my professional life I came across a few tips for this technology that helped me making my code cleaner and less coupled.

Before creating this blog I owned another one in french where I posted a few articles related to Model validation for a form. I will expose the concept of these articles in this new blog post, in english this time. Maybe it will look obvious for you but I wish I knew these tips when I started working with ASP .NET MVC and this is why I’m creating this blog entry, it might help some of you.

The problem

I created the following form for example, which ask for a name and an IP address:

I created this form using a new empty MVC application in Visual Studio and here is the Index.cshtml view:

@model CodingTips.Web.Models.IPAddressModel
 
<h2>IP Address form</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <div>
        @Html.LabelFor(m => Model.Name):
    </div>
    <div>
        @Html.TextBoxFor(m => Model.Name)
        @Html.ValidationMessageFor(m => Model.Name)
    </div>
    <div>
        @Html.LabelFor(m => Model.IPAddress):
    </div>
    <div>
        @Html.TextBoxFor(m => Model.IPAddress)
        @Html.ValidationMessageFor(m => Model.IPAddress)
    </div>
    <input type="submit" />
}

The Model and the Controller are defined the following way at the moment:

public class IPAddressModel
{
    [Required]
    [Display(Name = "Your name")]
    public string Name { get; set; }
 
    [Required]
    [Display(Name = "Your IP address")]
    public string IPAddress { get; set; }
}
 
public class HomeController : Controller
{
    [HttpGet]
    public ActionResult Index()
    {
        return View();
    }
 
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Index(IPAddressModel model)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }
 
        return RedirectToAction("Validate");
    }
 
    [HttpGet]
    public string Validate()
    {
        return "Your IP address has been registered";
    }
}

As you can see I already put some validation logic that will only verify that the fields are not left empty. If the user fill the two text boxes he will be redirected to a page containing only a confirmation message, this is the final result.

But, as you probably guessed it, there are issues with this validation code, the IP address field can be filled with any string value and the Model will be valid. This is not what we desire, we want a more accurate validation for this field and this is what I will show in this article.

When I began working with ASP .NET MVC my first thought, when I encountered an issue like this one, was to add all the validation logic inside the POST action of the Controller. Well, it can work but this is not the place to do so, this option increase the code coupling especially when the Model to validate is huge. In my opinion the Controller should only take care of the “flow” logic of the application and the validation should be placed somewhere else.

The good news is that ASP .NET MVC has been designed to be extensible for Model validation in an easy way. Let’s see how this can be done.

IValidatableObject

It is possible to add validation at the class-level, directly on the Model itself by implementing a specific interface: IValidatableObject. There is only one method available in this interface, the Validate() method. It will be automatically called by the MVC framework when the ModelState.IsValid code is executed, which is already present in our Controller. Let’s see the new version of the Model:

public class IPAddressModel : IValidatableObject
{
    [Required]
    [Display(Name = "Your name")]
    public string Name { get; set; }
 
    [Required]
    [Display(Name = "Your IP address")]
    public string IPAddress { get; set; }
 
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        const string regexPattern = @"^([\d]{1,3}\.){3}[\d]{1,3}$";
        var regex = new Regex(regexPattern);
 
        if (!regex.IsMatch(IPAddress))
            yield return new ValidationResult("IP address format is invalid", new[] { "IPAddress" });
    }
}

In this first implementation of the Validate() method I simply check that the given address match an IP V4 format (xxx.xxx.xxx.xxx). I have nothing else to do before being able to test this new behavior in my form.

ip-address-format-error

It works as expected. Yet, the validation is not over since I can put the value 800.800.800.800 (which is not valid for an IP address) without having any error, there is more validation to do:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    const string regexPattern = @"^([\d]{1,3}\.){3}[\d]{1,3}$";
    var regex = new Regex(regexPattern);
 
    if (!regex.IsMatch(IPAddress))
        yield return new ValidationResult("IP address format is invalid", new[] { "IPAddress" });
 
    string[] values = IPAddress.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
 
    byte ipByteValue;
    foreach (string token in values)
    {
        if (!byte.TryParse(token, out ipByteValue))
            yield return new ValidationResult("IP address value is incorrect", new[] { "IPAddress" });
    }
}

I extended the Validate() method in order to add more logic and to check that each element of the IP address has a correct value. I did this by checking that each of them can be transformed into a byte (value from 0 to 255).

ip-address-value-error

By using the IValidatableObject interface I was able to add validation logic to my Model without modifying my Controller. Doing so can be helpful when you have validation logic that depends on several properties of the Model.

In our example I used this interface only to check a single property and therefore it can look a bit “overpowered”. And if I have another form with a IP address field I will need to extract this part of the logic into a specific method to avoid code duplication. This point leads me to my next tip.

Custom attribute

To add validation to a specific field, the IP address one in our case, my advice will be to create a custom validation attribute. This will allow me to put the validation logic in one place only. Here’s the attribute implementation:

public class IpAddressAttribute : RegularExpressionAttribute
{
    public IpAddressAttribute()
        : base(@"^([\d]{1,3}\.){3}[\d]{1,3}$")
    {}
 
    public override bool IsValid(object value)
    {
        if (!base.IsValid(value))
            return false;
 
        string ipValue = value as string;
        if (IsIpAddressValid(ipValue))
            return true;
 
        return false;
    }
 
    private bool IsIpAddressValid(string ipAddress)
    {
        if (string.IsNullOrEmpty(ipAddress))
            return false;
 
        string[] values = ipAddress.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
 
        byte ipByteValue;
        foreach (string token in values)
        {
            if (!byte.TryParse(token, out ipByteValue))
                return false;
        }
 
        return true;
    }
 
    public override string FormatErrorMessage(string name)
    {
        return string.Format("The '{0}' field has an invalid format.", name);
    }
}

The logic is exactly the same as the one present in the IValidatableObject chapter. First checking the overall format with a regular expression and this is why I created a RegularExpressionAttribute subtype. Then the value of each byte is checked. Now I can use this attribute on my Model:

public class IPAddressModel
{
    [Required]
    [Display(Name = "Your name")]
    public string Name { get; set; }
 
    [IpAddress]
    [Required]
    [Display(Name = "Your IP address")]
    public string IPAddress { get; set; }
}

The Controller is unchanged, the Model is much cleaner and I can easily reuse my attribute for each IP address property in my application models without duplicating the logic.

My Model is now fully checked but only on the server-side, and this validation can clearly be done on the client-side as well with some JavaScript. This will avoid unnecessary HTTP requests between the browser and the server.

jQuery validation

ASP .NET now integrates a lot of third-party JavaScript libraries and among them there is jQuery which we will use to achieve client-side validation. I updated the _Layout.cshtml view to add the following lines:

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.3.min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.13.0/jquery.validate.min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/mvc/5.1/jquery.validate.unobtrusive.min.js"></script>

You can find different versions of these script here if you need specific ones. You also have to check that the Web.config is configured in order to enable client-side validation with jQuery:

<configuration>
  <appSettings>
    <add key="ClientValidationEnabled" value="true"/>
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
  </appSettings>
  ...
</configuration>

I can test the form again and see what is happening.

ip-address-jquery

The data have been checked without posting them to the server. This is possible because the @Html.TextBoxFor() method has generated the following HTML for the IP address field:

<input data-val="true" data-val-required="The Your IP address field is required." id="IPAddress" name="IPAddress" type="text" value="" aria-required="true" class="input-validation-error" aria-describedby="IPAddress-error IPAddress-error" aria-invalid="true">

The data-val-* attributes (HTML5) are used by the jquery.validate plugin to perform the client-side validation. But as you can see, there is nothing related to our regular expression pattern we defined for the IPAddressAttribute. And if you try to validate the form with an invalid IP address the form will still be posted to the server. At the moment the client-site validation is not complete.

IClientValidatable

ASP .NET MVC allow us to extend the generated HTML in order to add more control over the fields in the form. For that I will make the IpAddressAttribute implementing the IClientValidatable interface.

public class IpAddressAttribute : RegularExpressionAttribute, IClientValidatable
{
    public IpAddressAttribute()
        : base(@"^([\d]{1,3}\.){3}[\d]{1,3}$")
    {}
 
    public override bool IsValid(object value)
    {
        // does not change
        ...
    }
 
    private bool IsIpAddressValid(string ipAddress)
    {
        // does not change
        ...
    }
 
    public override string FormatErrorMessage(string name)
    {
        return string.Format("The '{0}' field has an invalid format.", name);
    }
 
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        string fieldName = metadata.DisplayName;
        string errorMessage = string.Format("The '{0}' field has an invalid format.", fieldName);
        const string pattern = @"^([\d]{1,3}\.){3}[\d]{1,3}$";
 
        ModelClientValidationRegexRule patternRule = new ModelClientValidationRegexRule(errorMessage, pattern);
        yield return patternRule;
 
        ModelClientValidationRule ipRule = new ModelClientValidationRule();
        ipRule.ValidationType = "ipformat";
        ipRule.ErrorMessage = string.Format("The '{0}' field has an invalid value.", fieldName);
 
        yield return ipRule;
    }
}

This method adds two new validation rule for the client-side code. The first one is for the regular expression and I use the existing ModelClientValidationRegexRule class to do so. The second one is a custom ModelClientValidationRule for which I defined the type as “ipformat”. This means that the input in the form will have a data-val-ipformat attribute.

This attribute is not recognized by the jQuery validation plugin, so I created a IPFormat.js file to extend it:

$.validator.unobtrusive.adapters.addBool("ipformat");
 
$.validator.addMethod("ipformat", function (value, element) {
    if (!value) {
        return false;
    }
    var bytes = value.split(".");
    if (bytes.length != 4) {
        return false;
    }
    for (i in bytes) {
        var entry = bytes[i];
        if (!entry) {
            return false;
        }
        var byte = parseInt(entry);
        if (isNaN(byte) || byte < 0 || byte > 255){
            return false;
        }
    }
    return true;
});

After including this file in my _Layout.cshtm view, I can see that the generated HTML for the text box has changed.

<script src="~/Scripts/Validators/IPFormat.js"></script>
<input data-val="true" data-val-ipformat="The 'Your IP address' field has an invalid value." data-val-regex="The 'Your IP address' field has an invalid format." data-val-regex-pattern="^([\d]{1,3}\.){3}[\d]{1,3}$" data-val-required="The Your IP address field is required." id="IPAddress" name="IPAddress" type="text" value="" aria-required="true" aria-invalid="true" class="input-validation-error" aria-describedby="IPAddress-error">

I now have my attributes for the regular expression validation and for the ipformat validation. Let’s try the form once again.

ip-address-jquery-custom

Here we are, the IP address is fully checked without being sent to the server. To achieve this I only used functionalities present in the framework, such as the IValidatableObject interface, the custom validation attributes, the IClientValidatable interface and a bit of jQuery.

This is the end of this blog post about Model validation in ASP .NET MVC on both server-side and client-side. I hope this will help you and as usual do not hesitate to comment and share this.

See you next time!

Coding Tips – Regex optimization in C#

coding-tipIn programming, manipulating strings can have serious impacts on your program performance, especially when using regular expression (regex). From what I found (links at the end), C# is not the best programming language to do this kind of operations.

I am not a regex expert but I know some tricks to increase performance when using them in .NET with C#. And this is what I’ll show you in this blog post. I started with the following piece of code :

public static class RegexComparer
{
    private const string REGEX_PATTERN = @"^[\w\d]+$";
    private const string REGEX_INPUT = "azertyuiop7894561230qsdfghjklm7894561230wxcvbn7894561230";
 
    public static bool StaticRegexMatch()
    {
        var match = Regex.Match(REGEX_INPUT, REGEX_PATTERN);
        return match.Success;
    }
}

The StaticRegexMatch() method will verify that the input is only made of alphanumeric characters by using the Regex class in a static way. I made a program that executes this function 500,000 times in a row and this is the result I get when looking at the execution time :

Static Regex Match
Executing action 500000 times
Elapsed time (ms) : 2713
Result is True

After this, I used the following code :

public static bool StaticCompiledRegexMatch()
{
    var match = Regex.Match(REGEX_INPUT, REGEX_PATTERN, RegexOptions.Compiled);
    return match.Success;
}
Static Compiled Regex Match
Executing action 500000 times
Elapsed time (ms) : 2404
Result is True

I gain in performance because knowing that the regex will be used several time I used the Compiled value of the RegexOptions parameter to specify the application to  store the regex in an assembly.

Last but not least solution :

private static Regex CompiledRegexInstance = new Regex(REGEX_PATTERN, RegexOptions.Compiled);
 
public static bool CompiledRegexInstanceMatch()
{
    var match = CompiledRegexInstance.Match(REGEX_INPUT);
    return match.Success;
}
Compiled Regex Instance Match
Executing action 500000 times
Elapsed time (ms) : 2317
Result is True

This time I used a specific instance in my class to match the input instead of the static Match() method and I kept the Compiled option. The performance gap is not as important as the first time but it is still better.

The pattern to match I chose in this example is quite simple and I can improve the performance of my code by using a different technique :

public static bool LinqMatch()
{
    return REGEX_INPUT.All(c => char.IsLetterOrDigit(c));
}
Linq Match
Executing action 500000 times
Elapsed time (ms) : 749
Result is True

As you can see, this approach is much more effective. The .NET char has several useful methods to validate data and combined with LINQ it can be very helpful for string operations.

Regular expressions are powerful features but are costly regarding execution time. Yet there are ways to improve their performance and sometimes the best answer is to avoid them if you can, depending on the pattern you want to match.

EDIT : You can find a link to a version of these examples with improvements on a gist made by Cybermaxs which I really thank (his answer is in the comments section).

Programming languages benchmark links :

As always, do not hesitate to share your ideas/remarks regarding this topic.

See you next time !

Coding Tips – Testing exceptions

coding-tip

Welcome to my new series entitled “Coding Tips”. The purpose of this new collection of articles is to share some tips related to programming I came across during my journey. These tips helped me and I still use some of them and maybe it can help you too.

If you are the same kind of developer as I am, you certainly like to write unit tests and a lot of them. You certainly also want to test every aspect of your code, including exceptions. But you might wonder if there is an easy way to test them, and of course there is !

Given the following (only for testing purpose) sample of code in C# :

public static class ClassToTest
{
    public static bool IsAQuestion(string toTest)
    {
        return toTest.EndsWith("?");
    }
}

The following call will throw a NullReferenceException :

ClassToTest.IsAQuestion(null);

So ? How to test this assertion ? Here is a common solution :

[TestMethod]
public void TryCatchTest()
{
    try
    {
        ClassToTest.IsAQuestion(null);
    }
    catch (NullReferenceException)
    {
        return;
    }
    Assert.Fail();
}

This test will pass only if a NullReferenceException is catched, otherwise it fails.

This solution looks a bit “heavy” for just testing an exception and this is why there is another solution much “lighter” than can be used. Please welcome the ExpectedExceptionAttribute :

[TestMethod]
[ExpectedException(typeof(NullReferenceException))]
public void AttributeTest()
{
    ClassToTest.IsAQuestion(null);
}

Yes, this is it, nothing more ! You can now test the exceptions with a single line of code. The .NET framework is full of helpful classes, the ExpectedExceptionAttribute is one of them but sometimes finding them is harder than using them.

If you use a different testing framework than Microsoft.VisualStudio.QualityTools.UnitTestFramework, it is likely that there is also a functionality allowing you to easily check the exceptions.

I hope you will like this new “Coding Tips” series, do not hesitate to share your ideas in order to improve it.

See you next time !