A small validation library for .NET that uses a fluent interface for building validations using Specification Pattern
In computer programming, the specification pattern is a particular software design pattern, whereby business rules can be recombined by chaining the business rules together using boolean logic. The pattern is frequently used in the context of domain-driven design.
- Easy to implement unit test, once you can test all specification separately;
- Easy to understand all business validation, once is more readable than a lot of "ifs" in one same code block;
- Easy to refactoring, once you can refactor only the one specification without interfere the others;
Install-Package DzfWeb.FluentSpecification
dotnet add package DzfWeb.FluentSpecification
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
For each business validation, create a new specification file with the validation
[SpecificationError(PersonValidation.InvalidName)]
public class PersonNameSpecification : Specification<Person>
{
public override bool IsSatisfiedBy(Person entity) =>
!string.IsNullOrEmpty(entity.FirstName) &&
!string.IsNullOrEmpty(entity.LastName);
}
[SpecificationError(PersonValidation.InvalidEmail)]
public class PersonEmailSpecification : Specification<Person>
{
public override bool IsSatisfiedBy(Person entity) =>
!string.IsNullOrEmpty(entity.Email) &&
new EmailAddressAttribute().IsValid(entity.Email);
}
Create a validator grouping all the specifications
public class PersonValidator : Validator<Person>
{
public PersonValidator(PersonNameSpecification personNameSpecification,
PersonEmailSpecification personEmailSpecification)
: base(personNameSpecification,
personEmailSpecification)
{ }
}
var result = _personValidator.IsValid(person);
foreach(var item in _personValidator.InvalidRules)
{
//item correspond to SpecificationErrorAttribute value defined on specification file
Console.WriteLine(item);
}
var isValidToSendEmail = _personValidator
.FilterRules(typeof(PersonEmailSpecification))
.IsValid(person);
var isValidToCreate = _personValidator
.AddParameter("RestrictedEmail", "douglas.franco@dzfweb.com.br")
.IsValid(person);
[SpecificationError(PersonValidation.InvalidEmail)]
public class PersonEmailSpecification : Specification<Person>
{
public override bool IsSatisfiedBy(Person entity) =>
!string.IsNullOrEmpty(entity.Email) &&
new EmailAddressAttribute().IsValid(entity.Email) &&
entity.Email != (string)Parameters.GetValueOrDefault("RestrictedEmail", "");
}
For more samples, visit: https://github.com/dzfweb/FluentSpecification/blob/master/FluentSpecification/FluentSpecification.Test/PersonTest.cs