FluentValidation and PostSharp for RESTful WCF parameter validation – Part 1

 

My current project involves publishing a RESTful WCF service, and its possible that parameters coming into the service could be incorrect. When this is the case one of two things should happen:

  • A HTTP response code and JSON payload returned to the client explaining the error.
  • The invalid parameter ignored and a default one used instead.

Since we are using FluentValidation elsewhere in the application it seemed like a logical choice for this project as well. It provides us with both a fluent interface for simple validation rules and a method of extension for custom rules.

For example let’s take a look at a fluent configuration for validating a request object.

public class CustomerIdValidator : AbstractValidator<string>
{
    public CustomerIdValidator()
    {
        RuleFor(s => s)
            .Cascade()
            .StopOnFirstFailure()
            .NotNull()
            .NotEmpty()
            .Length(32)
            .WithName("customerid")
            .WithMessage("Customer Id should be thirty two letter string.")
            .Must(IsStringAValidCustomerId)
            .WithName("customerid")
            .WithMessage("Customer Id is invalid.");
    }

    private static bool IsStringAValidCustomerId(string customerId)
    {
        Guid parseCustomerId;
        return Guid.TryParse(customerId, out parseCustomerId); ;
    }
}

Personally I find this easy to read without the messy conditional branching that we would have needed had we done this manually. You can apply rules to custom objects too.

public class BasketItemValidator : AbstractValidator<BasketItem>
{
    public BasketItemValidator()
    {
        RuleFor(basketItem => basketItem.CustomerId)
            .SetValidator(new CustomerIdValidator());

        RuleFor(basketItem => basketItem.Price)
            .NotEmpty()
            .WithName("price");

        RuleFor(basketItem => basketItem.Quantity)
            .GreaterThan(0)
            .WithName("quantity");

        RuleFor(basketItem => basketItem.ProductId)
            .SetValidator(new ProductIdValidator());

        RuleFor(basketItem => basketItem.ItemType)
            .Must(itemType => Enum.IsDefined(typeof (BasketItemType), itemType))
            .WithName("itemtype");
    }
}

Reusing existing validators using the SetValidator extension is a neat way of reusing validaiton routines. However there are some cases where you do need more complex logic, and FluentValidation luckily has us covered.

public class BasketItemListValidator : AbstractValidator<IEnumerable<BasketItem>>
{
    public override ValidationResult Validate(IEnumerable<BasketItem> instance)
    {
        var failures = new List<ValidationFailure>();

        if(instance == null || !instance.Any())
        {
            failures.Add(new ValidationFailure("basketItems", 
                "There should be at least one basket item to move."));
        }
        else
        {
            foreach (var basketItem in instance)
            {
                failures.AddRange(new BasketItemValidator().Validate(basketItem).Errors);
            }
        }

        return new ValidationResult(failures);
    }
}

We can simply override the Validate method to apply our custom routines, which in this case is applying an existing validator to a list of objects and collating the results.

If you need a validation framework I can recommend this one whole heartedly. Next up is using PostSharp to apply these routines when a call is made to WCF.

blog comments powered by Disqus