FluentValidation and PostSharp for RESTful WCF parameter validation – Part 4

 

This is the last of the series and you can find the previous parts below:

FluentValidation and PostSharp for RESTful WCF parameter validation – Part 1
FluentValidation and PostSharp for RESTful WCF parameter validation – Part 2
FluentValidation and PostSharp for RESTful WCF parameter validation – Part 3

The promised example solution at: https://github.com/naeemkhedarun/WcfValidation 

You will need PostSharp 2.0 installed, the community edition is fine.

This is a functional RESTful WCF service where you can send a product using a JSON request, and have the same product sent back in the response.

[RestArgumentValidation]
public ProductItem Create([ProductItemValidator] ProductItem instance)
{
    return new ProductItem
               {
                   Name = instance.Name
               };
}

On my current project we use a structure similar to the sample project to organise our attributes and validators.

image

To test this service I’m using the REST Console application for Chrome. First we need to set up our target:

image

When we make the request we should get a helpful HTTP Status Code of 400 (Bad Request):

image

We should also get a response body giving us some more detail about the issue with our request.

image

To make a valid request, we simply send the correct request body which looks like:

image

image

Running the request once more we receive the proper response:

image

And there you have it, I hope you’ve found this useful!

FluentValidation and PostSharp for RESTful WCF parameter validation – Part 3

 

Now we can take a look at how to take advantage of everything we have put in place. As mention in the first post, two thing can happen after a validation failure:

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

So our PostSharp aspect needs to handle both of these cases.

[DataContract]
public class ErrorMessage
{
    public ErrorMessage()
    {
        Errors = new List<string>();
    }

    [DataMember]
    public string ParameterName { get; set; }
    
    [DataMember]
    public ICollection<string> Errors { get; set; }
}

This is the object that is serialised back to the client in the event of a failure with no default value. Now we need to override the OnInvoke method in order to apply our runtime interception.

public override void OnInvoke(MethodInterceptionArgs args)
{
    var errorMessage = new List<ErrorMessage>();            
    Arguments arguments = args.Arguments;

    foreach (var parameterValidation in _validationRules)
    {
        foreach (var validatorType in parameterValidation.ValidationRules)
        {
            var result = ValidateArgument(validatorType, arguments[parameterValidation.Parameter.Position]);

            if (result != null && !parameterValidation.HasDefaultValue)
            {
                var message = new ErrorMessage
                                  {
                                      ParameterName = parameterValidation.Parameter.Name
                                  };
                foreach (var validationFailure in result)
                {
                    message.Errors.Add(validationFailure.ToString());
                }
                errorMessage.Add(message);
            }
            else if(result != null)
            {
                args.Arguments.SetArgument(parameterValidation.Parameter.Position, parameterValidation.DefaultValue());
            }
        }
    }

    if(errorMessage.Any())
    {
        throw new WebFaultException<List<ErrorMessage>>(errorMessage, HttpStatusCode.BadRequest);                
    }

    base.OnInvoke(args);
}

So we iterate through the validation rules, where each rule composes of a parameter, the default value if there is one and the rules which should apply to it. We check whether the actual value passes the rule, and if there are any failures raise a WebFaultException available in the .NET 4 BCL.

In the cause of a failure which does have a default value defined, we use PostSharp to override the actual value with the default one before returning to the intercepted method.

The ValidateArgument method looks like:

static IEnumerable<ValidationFailure> ValidateArgument(Type validatorType, object argument)
{
    IValidator validator = (IValidator) Activator.CreateInstance(validatorType, null);

    var result = validator.Validate(argument);
    if (!result.IsValid)
    {
        return result.Errors;
    }
    return null;

}

This calls upon FluentValidation to perform the checking and returns the result.

In the event of a failure with no default value, the client get a nice HTTP Status code indicating an error…

clip_image002

And a message detailing why…

clip_image002[5]

Next up will be a sample solution up on GitHub.

FluentValidation and PostSharp for RESTful WCF parameter validation – Part 2

 

Now that we have introduced FluentValidation in the previous post we can take a look at applying these based on attributes applied to the incoming WCF parameters. Let’s take a simple method and apply some parameters to it.

[RestArgumentValidation]
public Basket Basket(
    [CustomerIdValidator] string customerid,
    [BasketItemValidator] BasketItem basketItem)
{
    // Stuff happens
}

While these attributes do clutter the code, personally I feel they make it clear these parameters are being validated. Let’s take a look at what these parameter attributes are before looking at the PostSharp.

First we need a base class for the attributes to provide both a default value if needed, and what validators should apply to the decorated parameter.

[Serializable]
public abstract class RestArgumentValidatorBase : Attribute
{
    public abstract IEnumerable<Type> Validators { get; }

    public virtual Func<object> DefaultValue { get; private set; }
}

The reason we need to define a function that returns the default value is because PostSharp serialises these attributes as an optimisation. If the default value is based on an expression which can only be calculated at runtime, then we cannot serialise it, but we can serialise the expression which computes this value. Let’s take a look at some examples of this in action:

public class BasketItemValidatorAttribute : RestArgumentValidatorBase
{
    public override IEnumerable<Type> Validators
    {
        get
        {
            return new[]
                       {
                           typeof(BasketItemValidator)
                       };
        }
    }
}

Here we specify the validator used for the object BasketItem, and no default value. This means if the validation fails a response will be sent to the client indicating what has gone wrong.

public class CurrencyValidatorAttribute : RestArgumentValidatorBase
{
    public override Func<object> DefaultValue
    {
        get { return () => ConfigurationManager.AppSettings["defaultCurrency"]; }
    }

    public override IEnumerable<Type> Validators
    {
        get { return new[] { typeof(CurrencyValidator) }; }
    }
}

Here we specify a default value which is taken from the app settings, so if an invalid parameter is sent down, we can use this value instead. All that’s left is the PostSharp aspect which ties all this together which we can go through step by step.

First we need to analyse the method which has the aspect applied to see what validation needs to happen. We can compute this ahead of time during compilation so the runtime overhead is reduced.

public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
{
    foreach (var parameterInfo in method.GetParameters())
    {
        var validationAttribute = (from attributeType in parameterInfo.GetCustomAttributes(true)
                                   where typeof(RestArgumentValidatorBase).IsAssignableFrom(attributeType.GetType())
                                   select attributeType).Cast<RestArgumentValidatorBase>().FirstOrDefault();

        if(validationAttribute != null)
        {
            _validationRules.Add(new ParameterValidation
                                     {
                                         Parameter = parameterInfo,
                                         DefaultValue = validationAttribute.DefaultValue,
                                         ValidationRules = validationAttribute.Validators
                                     });
        }
    }
}

This can be summarised as:

  1. Take a look at each parameter on the method.
  2. See if it has a validation attribute applied.
  3. Cache the default value expression and validation rules for that parameter in a serialised list which is used at runtime.

The cached serialised object itself looks like:

[Serializable]
class ParameterValidation
{
    public ParameterInfo Parameter { get; set; }

    public Func<object> DefaultValue { get; set; }

    public bool HasDefaultValue
    {
        get
        {
            return DefaultValue != null;
        }
    }

    public IEnumerable<Type> ValidationRules { get; set; }
}

Next up we’ll take a look at using this cached information at runtime.

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.

Older Posts