Model validation filter in ASP .NET Web API

Most Web applications need to be able to accept and save data, and any serious application must perform all sorts of validations before taking information and attempt to store it. Luckily for us (.Net developers at least), the days of manual, imperative validation are gone for good.

Thanks to Data Annotations, model validation and error messages have become easy and consistent. We can pick from the built in validation attributes in the System.ComponentModel.DataAnnotations namespace (such as RequiredAttribute, StringLengthAttribute, CompareAttribute) or roll our own, and then declare our intention to validate our objects properties by decorating them with the corresponding attributes. This validation mechanism is plugged right into the core of ASP NET MVC and Web API, so we can check right away if a model entity passed to a controller action is valid or not:

// MyModel.cs file
using System.ComponentModel.DataAnnotations;

public class MyModel
{
	[Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "MyModel_Name")]
	public string Name { get; set; }

	[EmailAddress]
	public string Email { get; set; }
}

// MyController.cs file
using System.Web.Http;

public class MyController : ApiController
{
	public HttpResponseMessage Post(MyModel model)
	{
		if (ModelState.IsValid)
		{
			// Work with the object
			_repository.Save(model);
			return new HttpResponseMessage(HttpStatusCode.OK);
		}
		else
		{
			var errors = ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage)).ToArray();
			return Request.CreateResponse(HttpStatusCode.BadRequest, new { errors });
		}
	}
}

Easy, huh? But, if you are as lazy (or practical) as me, and don’t want to keep checking your model validity in every action, you can centralize that logic in only one place and then apply it wherever you like. Just create an ActionFilterAttribute:

using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

public class ModelValidationFilterAttribute : ActionFilterAttribute
{
	public override void OnActionExecuting(HttpActionContext actionContext)
	{
		if (!actionContext.ModelState.IsValid)
		{
			var errors = actionContext.ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage)).ToArray();
			actionContext.Response =
				actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, new { errors });
		}
	}
}

And on your controllers:

public class MyController : ApiController
{
	[ModelValidationFilter]
	public HttpResponseMessage Post(MyModel model)
	{
		// No need to check for validity (if model is not valid, the method will not be called)
		_repository.Save(model);
	}
}

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