Introducing my ASP.Net Web API Request Validator

Hackered
Monday, October 6, 2014
by Sean McAlinden

What's this all about then?

I have found that most projects I have worked on with ASP.Net Web API have required a custom model returned when certain preconditions have not been met such as missing properties etc. In ASP.Net MVC we can utilise DataAnnotations on our models which nicely validates the model and populates the ModelStateDictionary for us, we then return the model to the view and all is good. This is on top of the fact that it can also generate client side validation for us as well, all in all a really nicely packaged solution.

What about ASP.Net Web API?

In WebAPI we can use DataAnnotations however by default this will not return a failing response without some manual intervention. Hooking up an action filter to return the model state dictionary as the response is pretty straight forward however so far I have not come across a client who would be happy to return the model state dictionary serialized structure:

{
    "testModel.Name":{
    "Value":null,
    "Errors":[
        {"Exception":null,"ErrorMessage":"The Name field is required."}
    ]},
    "testModel.Age":{
    "Value":null,
    "Errors":[
        {"Exception":null,"ErrorMessage":"The field Age must be between 10 and 20."}
    ]}
}

How on earth can we solve this disaster?

Well, there are plenty of ways this can be solved, in my case it has quite often been custom validation services injected into the controller or custom per app versions of the new library I am about to show you. I have packaged up my most common cases into a library called the ASP.Net Web API Request Validator which can be found on NuGet https://www.nuget.org/packages/ASPNetWebAPIRequestValidator. There are a number of ways it can be used, in this post I will show you a fairly simple but most common case where the information within the ModelStateDictionary is returned in a custom model. For more ways to use the library, check out the documentation at http://embarr-development.co.uk/labs/asp-net-web-api-validator. The source is available at BitBucket: https://bitbucket.org/embarr-development/asp.net-web-api-request-validator.

Create the Custom Validation Models

Lets say we want to create a nice simple structure which would return the following style output:

[
    {
        "Property" : "Name",
        "ErrorMessages" :
            [
                { "Message" : "The Name field is required." } 
            ]
    },
    { 
        "Property" : "Age",
        "ErrorMessages" :
            [ 
                { "Message" : "The field Age must be between 10 and 20." } 
            ]
    }
]

Create the following models:

public class ValidationError
{
    public string Property { get; set; }
    public List<Error> ErrorMessages { get; set; }

    public ValidationError()
    {
        ErrorMessages = new List<Error>();
    }
}

 

public class Error
{
    public string Message { get; set; }
}

These models will form the structure of each validation error, so essentially you will receive an array of these as the validation error response.

Hook it up

Make sure you have pulled in the library via NuGet https://www.nuget.org/packages/ASPNetWebAPIRequestValidator. In your WebApiConfig class or Application_Start method (or wherever you like to set up your web api cofiguration) add the following code:

RequestValidator.Create<ValidationError>()
    .MapPropertyName(x => x.Property)
    .MapPropertyErrorMessagesCollection(x => x.Errors)
    .Map(x => x.Message).ToErrorMessage()
    .Init(config);

Explanation:

  • First pass the type of your validation error model to the create method.
  • Map the property name (this will map the ModelState item property name to the property on your class where you would like the property name to be populated).
  • Map the error messages collection (this lets the library know which property on your class will store the collection of error messages).
  • The .Map function specifies a particular property on your Error Collection type where you would like to map the error message (there are other things you can do here which I'll cover in future posts).
  • ToErrorMessage tells the library to just map the error message from ModelState directly to the property specified in the previous .Map expression.
  • the Init method accepts the HttpConfiguration. (Under the scenes it is creating a global filter, if you're interested take a look at the source).

Try it out

At this point you are hooked up and ready to go, create an API controller with a model with some DataAnnotation for example:

public class MyModel
{
    [Required]
    public string Name { get; set; }

    [Range(10, 20)]
    public int Age { get; set; }
}

Spin up your solution and send a request which will fail the validation DataAnnotations you have added and voila, you will receive the model state errors in your custom serialized format. Hope you find this useful, let me know if you have any issues or suggestions for improvements.