Cleaning Up Actions with ModelBinders

In my last post I showed a controller action which contained a lot of boilerplate code. When the action of a controller accepts the id of an entity the first section of code of that action is always …

  1. Make sure the id exists, if not show error or 404
  2. Make sure that the id references a valid entity in the database, if not show error or 404
  3. If the first two evaluated false then get the entity from the database an continue on with your action

This can get tedious and the extra “noise” takes away from what your controller is trying to accomplish. We are going to use component of the ASP.NET MVC framework called a model binder to help us encapsulate this code. A model binder will get the id that was passed in the GET parameters, find the entity that matches the id and pass it into the action as a parameter. Take our original controller action …

public ActionResult Details(int? id = null)
{
// Make sure that we have an id
if (!id.HasValue)
{
return HttpNotFound();
}

// Get the entity from the repository with the id
var entity = _repository.GetById(id.Value);

// Make sure that the entity exists
if (entity == null)
{
return HttpNotFound();
}

// Do stuff with the entity
}

Which will turn into this after we configure the model binder …

public ActionResult Details(Entity entity)
{
// Make sure that the entity exists
if (entity == null)
{
return HttpNotFound();
}

// Do stuff with the entity
}

So how does this magic happen? Does the framework automatically grab the entity from the database? Well not really but it only requires a small amount of code. First we need to implement the IModelBinder interface. The interface only contains one method, the BindModel method. Here is an example implementation of it for our entity model class …

public class EntityModelBinder : IModelBinder
{
private readonly IEntityRepository _repository;

public EntityModelBinder(IEntityRepository repository)
{
_repository = repository;
}

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
//Doesn't have an id so just return null
if (!controllerContext.RouteData.Values.ContainsKey("id"))
{
return null;
}

string value = controllerContext.RouteData.Values["id"] as string;

//Not sure if this will happen but check for it anyway
if (value == null)
{
return null;
}

int id;

//Parse the integer
if (int.TryParse(value, out id))
{
return _repository.GetById(id);
}

return null;
}
}

Then add this code to the Application_Start() method of the Global.asax file.

ModelBinders.Binders.Add(typeof(Entity), new EntityModelBinder());

And there you go. Now you can automattically pull fetch entities from the database by just putting one as the parameter for your controller’s action. In the next blog post I will be talking about removing that null check from the controller’s actions. Happy Codding.

Leave a comment

Your email address will not be published. Required fields are marked *