I’ve seen a lot of people (myself included), completely miss out on the magic of ModelBinders in MVC3.
The problem:
Take this very regular piece of code:
[HttpPost]
public ActionResult Edit(FormCollection collection)
{
var model = new Foo();
if (collection["Id"] != null)
{
model = _repository.Get(Guid.Parse(collection["Id"]));
}
// Set properties
model.Name = collection["Name"] ?? model.Name;
// do other business logic
_mailer.Send(new MailMessage());
// save
_repository.Save(model);
return RedirectToAction("Index");
}
We can see that this code is laden with stuff that you’re likely to do in other controllers. Wouldn’t it be nice if you could do something like:
[HttpPost]
public ActionResult Edit(Foo model)
{
// do business logic
_mailer.Send(new MailMessage());
// save
_repository.Save(model);
return RedirectToAction("Index");
}
Much nicer! We’ve cut out all the middle crap and gone straight to the business logic of the controller. This makes it much easier to figure out what the method is actually doing.
The solution:
This can be done by implementing the IModelBinder. There are plenty of other resources on how to do this. But we want a solution that we can use with our favorite IOC container.
First we create our model binder:
[ModelBinderType(typeof(Foo))]
public class TaskBinder : IModelBinder
{
private IRepository _fooRepo;
public TaskBinder(IRepository fooRepo)
{
if (fooRepo == null) throw new ArgumentNullException();
_fooRepo = fooRepo;
}
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var collection = new FormCollection(controllerContext.HttpContext.Request.Form);
var model = new Foo();
if (collection["Id"] != null)
{
model = _taskRepo.Get(Guid.Parse(collection["Id"]));
}
model.Name = collection["Name"] ?? model.Name;
return model;
}
}
Note the ModelBinderType attribute on our class that tell Autofac what type of model we’re binding.
Then we just make sure that the binder is picked up by Autofac in our Global.aspx. Ensure you have these 2 lines in Application_Start, where you’re building your container:
builder.RegisterModelBinderProvider(); builder.RegisterModelBinders(typeof(MvcApplication).Assembly);
That’s all there is too it!
-
raynerw posted this