ASP.Net Web API: Utilising ModelState and DataAnnotations to create detailed precondition validation errors

Hackered
Friday, September 12, 2014
by Sean McAlinden

One of the great benefits of using the MVC framework is the ability to add data annotations to your view model to control the display of validation messages. Before data annotations and the model binder we had to write reams of sleep inducing validation code, however validation quite often became a real second class citizen due to the sheer amount of effort it would take to get it right.

Over to Asp.Net Web API

Interestingly enough, when Asp.Net Web API was released, most of us quickly adopted the previous approach of hand crafting precondition validation, mainly due to it not working "out-of-the-box". In this post I am going to show how simple it is to make use of data annotations and model state in Asp.Net Web API. I am going to do a really simple version where it will pretty much just work, in a later post I'll create a more controlled version where the output is a custom object.

Really simple version

Create a simple model with validation rules:

public class PersonRequestViewModel
{
    [Required]
    [StringLength(25, ErrorMessage = "Your name is way too long")]
    public string FirstName { get; set; }
}

Create an ApiController:

[RoutePrefix("validation/sample")]
public class ValidationSampleController : ApiController
{
    [Route("simple/example")]
    public IHttpActionResult Post(PersonRequestViewModel personRequestViewModel)
    {
        return Created("http://tempuri.org","Okidoke");
    }
}

IMPORTANT: Try and say the route url 10 times as fast as you can

Then we need to create a ValidateModelAttribute class:

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (!actionContext.ModelState.IsValid)
        {
            actionContext = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
        }
    }
}

What is it doing?

  1. Checks if the model state is valid (same as you do in MVC)
  2. If it is not valid, create and return a new httpResponseMessage with a 400 status code and the model state object.

Hook it up

You could just place this attribute above methods etc. however it is much better to hook this up globally. You should probably do this in a FilterConfig style class but for this post I have hooked up the ValidateModelAttribute in the WebApiConfig class:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();

        config.Filters.Add(new ValidateModelAttribute());
    }
}

Run it up and perform the http request:

The response:

{ 
  "Message" : "The request is invalid.",
  "ModelState" : { "personRequestViewModel.FirstName" : [ "Your name is way too long" ] }
}

Conclusion

So far so good, we are leveraging data annotations to return useful validation messages to our Asp.Net Web API consumer. In a future post I'll demonstrate how to take control over the output.