Validating Models with Fluent Validation

If you have model class and if that needs to be validated we need to explicitly write logic so initial days we were using Data Annotations and this is how code looked like

 

    using System;
    using System.ComponentModel.DataAnnotations;

    public class Contact
    {
        public string FirstName { get; set; }

        public string MiddleName { get; set; }

        [Required]
        public string LastName { get; set; }

        [EmailAddress]
        public string Email { get; set; }

        public string Mobile { get; set; }

        public string Phone { get; set; }

        public DateTime BirthDate { get; set; }

        public DateTime AnniversaryDate { get; set; }

        [Required]
        public Address HomeAddress { get; set; }

        public Address OfficeAddress { get; set; }
    }

    public class Address
    {
        public string Line1 { get; set; }

        public string Line2 { get; set; }

        public string City { get; set; }

        public string County { get; set; }

        [Required]
        public string Postcode { get; set; }
    }

This way programming is good if Model validation is not going to change. What if you want various/different validations & unit test the model? For example based on some condition you want to disable required field validation

To solve this we have FluentValidation which is available in NuGet with Apache2 License. So here is how the model class going to look with no data annotations attributes

 

    using System;

    public class Contact
    {
        public string FirstName { get; set; }

        public string MiddleName { get; set; }

        public string LastName { get; set; }

        public string Email { get; set; }

        public string Mobile { get; set; }

        public string Phone { get; set; }

        public DateTime BirthDate { get; set; }

        public DateTime AnniversaryDate { get; set; }

        public Address HomeAddress { get; set; }

        public Address OfficeAddress { get; set; }
    }

    public class Address
    {
        public string Line1 { get; set; }

        public string Line2 { get; set; }

        public string City { get; set; }

        public string County { get; set; }

        public string Postcode { get; set; }
    }

Here we have separated the validation logic so that it(model) can be reused & unit tested

    using ConsoleApplication.Model;
    using FluentValidation;

    public class ContactValidator : AbstractValidator<Contact>
    {
        public ContactValidator()
        {
            RuleFor(x => x.LastName).NotEmpty().WithMessage("Last name cannot be blank");
            RuleFor(x => x.Email).EmailAddress().WithMessage("Not a valid Email");
            RuleFor(x => x.Mobile).NotEmpty();
            RuleFor(x => x.HomeAddress).NotNull().SetValidator(new AddressValidator());
            RuleFor(x => x.OfficeAddress).SetValidator(new AddressValidator());
        }
    }

    public class AddressValidator : AbstractValidator<Address>
    {
        public AddressValidator()
        {
            RuleFor(x => x.Postcode).NotNull().NotEmpty();
        }
    }

If you notice code above if you want custom message to displayed it can be done WithMessage method.

The below code is explained using console application and there are ASP.NET MVC packages available in NuGet as well.

    using ConsoleApplication.Model;
    using ConsoleApplication.Validator;
    using System;

    internal class Program
    {
        private static void Main(string[] args)
        {
            var contact = new Contact { LastName = "Husy", Email = "husy@zealups.com", BirthDate = new DateTime(1983, 1, 3) };
            var contactValidator = new ContactValidator();
            var result = contactValidator.Validate(contact);
            if (!result.IsValid)
                foreach (var item in result.Errors)
                {
                    Console.WriteLine(item.ErrorMessage);
                }
            Console.ReadLine();
        }
    }

The output of the code is
‘Mobile’ should not be empty.
‘Home Address’ must not be empty.