Sunday, August 22, 2010

Controller Action Design in MVC

Validate, Act, Translate, and Respond. That’s about it.
I’ve been trying to come up with a nice acronym for how to structure code in Actions for some time now, and this is the best I have managed. I wish it spelt a nice word – so if you’ve a better suggestion shout up. What I’m trying to say is – “don’t stuff all your business logic and all sorts of other code into your controller” and, “follow a common, clear pattern to writing your controller actions”. This is similar to the AAA acronym for unit testing; Arrange, Act, and Assert; which really helps developers focus when writing tests. Therefore, my slightly awkward VATR acronym suggests that in an MVC action you;

1.       Validate; check the input, either through automatic model binding, explicit validation checks, or a combination of both.
2.       Act; apply the business logic – save, fetch data, etc.
3.       Translate; convert entities returned from the business logic into View Model entities. See this post if you want to understand the motivation for this further.
4.       Respond; render a view, or redirect to another action, etc.

   This does not include “inspect database” or “loop through all posted data and….” steps, because I believe they should be encapsulated in the business logic, and therefore not in your controller. It also doesn’t include authorisation, error handling, or other concerns that can be handled with filters etc. Let’s take some example code and see what I mean.
Example 1: The Simple Case

Taking a typical Index action, perhaps for a blog site;



  1. public
     ActionResult Index()  
  2. {  
  3.    var articles = _logic.GetLatestArticles();  
  4.    var model = new HomeIndexViewModel  
  5.    {  
  6.        Articles = Mapper.Map(articles),  
  7.        Today = DateTime.Today,  
  8.        Username = UserInfo.Username  
  9.    };  
  10.    return View(model);  
  11. }  


In this example, there is no data input directly to the action, so Validate is notable by it’s absence. Anything the action uses should be validated of course, such as the Username retrieved from a helper class; but that validation is encapsulated elsewhere. Next, we Act -  by calling the GetLatestArticles method in my business logic. This returns a list of article business entities.
I don’t want to pass these business entities to the view (why?), so we Translate them into a View Model using a helpful Mapper class. And finally, we Respond with a command to render a view using our View Model.

Example 2: A POST Action

Upping the complexity slightly, let’s consider a POST that needs to save some data;


  1. [HttpPost]  
  2. public ActionResult Display(HomeDisplayViewModel model)  
  3. {  
  4.    if (ModelState.IsValid)  
  5.    {  
  6.        _logic.UpdateArticle(model.Article);  
  7.        return RedirectToAction("Index");  
  8.    }  
  9.    else  
  10.        return View(model);  
  11. }  


Read more: UK Premier Support for Developers