Using validation attributes in .NET Core

There are a number of ways you can implement validation of your forms, models or uploads. One of the most common methods of doing that is using validation attributes. Not only are they very easy to use, they can also be customized freely according to your business’ requirements. Today we’ll take a closer look at how to use them based on a real-life example from our project.

First look – Attributes

Let’s take a look at the AccountViewModel, a class in our project that’s used mostly for registering new users.

public class AccountViewModel
   {
       [Required]
       [Display(Name = "Display name")]
       public string DisplayName { getset; }
 
       [Display(Name = "Avatar image")]
       public byte[] AvatarImage { getset; }
 
       [Required]
       [EmailAddress]
       [Display(Name = "Email")]
       public string Email { getset; }
 
       [Required]
       [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at most {1} characters long.", MinimumLength = 8)]
       [DataType(DataType.Password)]
       [PasswordValidation]
       [Display(Name = "Password")]
       public string Password { getset; }
 
       [DataType(DataType.Password)]
       [Display(Name = "Confirm password")]
       [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
       public string ConfirmPassword { getset; }
   }

We have several data fields that are heavily decorated with various attributes written in [brackets]. Some of them are just metadata information like [DataType]; we use them to tell the application how to format and display that data. For example a string with a [DataType(DataType.Password)] attribute will be displayed as *** instead of visible characters, [DataType(DataType.DateTime)] will be displayed according to rules of formatting date, et cetera. There are many predefined [DataType] attributes and it’s worth it to take a closer look at them – they are listed >here<. I’m sure that list will cover most of your needs.

Second step – Validation Attributes

Some attributes are used strictly for validation. In the example above we have [Required], or [StringLength] – these place a restriction on data. The [Required] attribute would determine state of the model to be invalid if at least one field with the [Required] attribute is left blank by the user in the HTML form. Attributes can be further customized: you can add int parameters to [StringLength] to specify the minimum and maximum lengths of the string, and a custom error message that will be displayed to the user in case of the validation failure. One of the most widely used validation attribute is [Compare], allowing you, as in the example above, to compare two strings and to determine if they are equal – important if you want to make sure that the user didn’t make a mistake while entering his or her password.

Finally there – Custom Validation Attributes

But what should we do in the most likely scenario that the predefined validation attributes are not suited for our needs? The solution for that is the custom validation attributes, a way for us to define our own attributes and use them for validation. We should start by creating a new folder called “Attributes” and a new class inheriting from ValidationAttribute. The widely used convention for the class name is FooValidationAttribute, resulting in a creation of [FooValidation] so we’ll be sticking to that as well. Our custom validation attribute class should itself be decorated with an attribute, telling the application that we are going to use it to decorate data fields. Let’s take a look at the example from our project:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
   public class UploadValidationAttribute : ValidationAttribute
   {
       private string FileIsNull = "No file uploaded!";
       private string FileTooBig = "Uploaded file is too big (maximum size is " + MaximumFileSize + " B)";
       private string FileIsNotImg = "This file is not in a supported format! (.jpg, .png, or .gif)";
 
       private const int MaximumFileSize = 1 * 512 * 1024; // equals to 0.5 MB
 
       protected override ValidationResult IsValid(object value, ValidationContext validationContext)
       {
           IFormFile file = value as IFormFile;
           if (file == null)
           {
               return new ValidationResult(FileIsNull);
           }
 
           if (file.Length > MaximumFileSize)
           {
               return new ValidationResult(FileTooBig);
           }
 
           string ext = Path.GetExtension(file.FileName);
           var isimg = false;
           switch (ext)
           {
               case ".jpg":  isimg = truebreak;
               case ".png":  isimg = truebreak;
               case ".jpeg": isimg = truebreak;
               case ".gif":  isimg = truebreak;
           }
 
           if (!isimg)
           {
               return new ValidationResult(FileIsNotImg);
           }
           return ValidationResult.Success;
       }
   }

This rather simple class demonstrates our implementation of the validation for uploading avatar images. We check for three things – if the file is null, if the file is bigger than the maximum allowed size and finally, if the file is an image (i.e. if it has one of the allowed file extensions). Custom validation attributes work by overriding IsValid method, receiving object for the validation, then returning ValidationResult with a custom error message when a check is failed or, in case everything is correct, a ValidationResult.Success. A small optimalization would be to place a check that is most likely to fail at the beginning of the method.

Summary

If we’re done with that, all that’s left to do now is to decorate our property-to-validate with our custom attribute [FooValidation]. We can use this implementation of validation in an MVC view by creating a span with asp-validation-for parameter and in controller thanks to the ModelState.IsValid call.

That’s all for now. I hope that tutorial will prove to be useful in your project and I wish you many validation successes! ;]

Leave a Reply

Your email address will not be published. Required fields are marked *