Fluent validations using the fluent decorator pattern

Validation on business objects is a responsibility that changes based on the requirements and sometimes gets added or removed based on the context.  The decorator design pattern can be utilized to provide various validations on business objects which can be attached to the object dynamically. In this post we’ll see how we can use the fluent decorator to implement fluent validations on an entity. We’ll create the base validate as a generic class so that it can be used on any entities in the application.
public class Order
{
    public stringOrderNumber { get; set; }
    public int OrderId { get; set; }
    public stringDescription { get; set; }
    public CustomerCustomer { get; set; }
    public DateTimeOrderDate { get; set; }
    public stringShipmentDetails { get; set; }
    public DateTime? RecievedDate { get; set; }
    public OrderStatusStatus { get; set; }
}
We’ll be using the Order object and validate it in this sample.
The interface IEnityValidator is used as the signature for our validation objects.
public interface IEntityValidator
{
    bool Validate();
    string GetErrorMessage();
    bool IsValid();
    List<ValidationError> GetErrors();
}
public class ValidationError
{
    public ValidationError(stringfield, string message)
    {
        Field = field;
        Message = message;
    }
    public string Field { get; set; }
    public string Message { get; set; }
}
The abstract EnityValidationDecorator is the base class for the validation decorators. All our decorators will inherit this class and implement the Validate method to do validations on the object passed to the validator.
public abstract class EntityValidationDecorator: IEntityValidator
{
    protected T _Entity;
    protected IEntityValidator_Validator;
    protected StringBuilder_messageBuilder = new StringBuilder();
    protected List<ValidationError> _Errors = new List<ValidationError>();
    protected EntityValidationDecorator(IEntityValidator validator)
    {
        var entityValidator = validator as EntityValidationDecorator;
        if (entityValidator != null) _Entity = entityValidator._Entity;
        _Validator = validator;
    }
    protected EntityValidationDecorator(T entity, IEntityValidator validator)
    {
        _Entity = entity;
        _Validator = validator;
    }
    public abstract bool Validate();
    public abstract string GetErrorMessage();
    public List<ValidationError> GetErrors()
    {
        if (_Validator == null) return _Errors;
        _Errors.AddRange(_Validator.GetErrors());
        return _Errors;
    }
       
    public abstract bool IsValid();
}
Implementing the Order number validator.
public class OrderNumberValidator : EntityValidationDecorator<Order>
{
    public OrderNumberValidator(IEntityValidatorvalidator) : base(validator)
    {
    }
    public override bool Validate()
    {
        _Validator.Validate();
        string validationMessage;
        var orderNumber = _Entity.OrderNumber;
        if(string.IsNullOrEmpty(orderNumber))
        {
            validationMessage = “Order number cannot be empty”;
            GetErrors().Add(new ValidationError(“OrderNumber”, validationMessage));
            _messageBuilder.AppendLine(validationMessage);
            return false;
        }
        if(orderNumber.Length < 5)
        {
            validationMessage = “Order number should be greater than 5”;
            GetErrors().Add(new ValidationError(“OrderNumber”, validationMessage));
            _messageBuilder.AppendLine(validationMessage);
            return false;
        }
        return true;
    }
    public override string GetErrorMessage()
    {
        return string.Concat(_Validator.GetErrorMessage(), _messageBuilder.ToString());
    }
    public override bool IsValid()
    {
        return !GetErrors().Any();
    }
}
Similarly we can use different kinds of validators for performing validations on our Order object. Later we can add fluent interface support to the validations by using extension methods as given below.
public static class OrderDecoratorExtensions
{
    public static EntityValidationDecorator<Order> AttachValidator(thisOrder order)
    {
        return new OrderValidator(order);
    }
    public static EntityValidationDecorator<Order> AddOrderNumberValidation(this EntityValidationDecorator<Order> validator)
    {
        return new OrderNumberValidator(validator);
    }
    public static EntityValidationDecorator<Order> AddOrderCustomerValidation(this EntityValidationDecorator<Order> validator)
    {
        return new OrderCustomerValidator(validator);
    }
    public static EntityValidationDecorator<Order> AddOrderDateValidation(this EntityValidationDecorator<Order> validator)
    {
        return new OrderDateValidator(validator);
    }
}
Testing the validators.
[TestMethod]
public voidOrderNumberShouldNotBeEmpty()
{
    var order = new Order();
    var orderValidator = order.AttachValidator()
        .AddOrderNumberValidation()
        .AddOrderCustomerValidation()
        .AddOrderDateValidation();
    var isValid = orderValidator.Validate();
    var errorMessage = orderValidator.GetErrorMessage();
    Assert.IsTrue(errorMessage != string.Empty);
    Assert.IsFalse(isValid);
}

via Thoughts of a .NETer http://blogsprajeesh.blogspot.com/2012/08/fluent-validations-using-fluent.html

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s