After watching this video, I am wondering if I am using my controllers wrong. What exactly should a controller contain?
For my blog, I have a post controller which has methods:
create
show
list
loadPost
like
dislike
Whereas my post model only has a few access rules, validation rules and relation information. Are there any examples of a MVC app on the web?
I highly recommend reading
http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/04/24/how-we-do-mvc.aspx
Here's my incomplete list of what controller shouldn't do:
- bind post data to view model - no, model binders should do this
- get entities from repositories - I'd say no, model binders or action filters should
- calculate something - no, view models or entities should
- authorization - maybe, but it's better pass to attributes/filters
- validation - only if it come back from entities/domain (i.e. business rules), view models (presentation) validation should be handled automatically (binders, etc)
Should do:
- get bound, validated view model as input
- call domain layer, passing data from view model
- handle domain layer errors
- route to appropriate action/view depending on view model / domain results
Bad:
public ActionResult PlaceOrder(Guid orderid)
{
if (HttpContext.Session["user"] == null)
return Redirect("Login");
if (!ValidOrderId(orderid)) return Redirect();
var order = cart.Get(orderid);
if (order == null) { ViewData["orderid"] = orderid; return View("Select"); }
order.Status = OrderStatus.Placed;
foreach (var item in order.Items)
item.Update();
var cart = Cart.GetCurrent();
cart.Save(order);
return Redirect("Show", "Orders", new { orderid = orderid });
}
Good
[Authorize]
[ModelStateToTempData]
// OrderViewModel.Id/OrderViewModel.Instance - validates id,
// gets it from repository, set Instance or ModelState error
public ActionResult PlaceOrder(OrderViewModel<Order> order)
{
if (!ModelState.IsValid)
return View("Select", order);
var order = order.InstanceFromDatabase;
_injectedCart.SetOrderPlaced(order);
return RedirectToAction<OrdersController>(c => c.Show(order));
}
And by the way, I rarely see good MVC examples, including the NerdDinner. They all deal with business logic inside actions, no view models, and so on. This is usually OK for what they are intendet for - MVC features demonstration - but it shouldn't be taken as good design examples. A more-or-less good examples is CodeCampServer, along with accompanion book ASP.NET MVC In Action. But not without its drawbacks (anemic domain model, for example).
But if do not try to follow domain driven design, and instead have a simple data-driven requirements, things can be easier for you.
I try to have fat viewmodels and thin controllers, the controller giving work to my business objects.
NerdDinner is a good sample app but StackOverflow is my favorite example of an MVC site.
Kindness,
Dan
A controller should contain enough logic to interpret what the user has said to do before passing processing off to a service layer.
So if a user says "Mark this post as one I like", by clicking the like button, the controller makes sure that user is authorized, and then let's the service layer handle actually doing the work of marking the post etc.
If the user says "create a new blog entry" then the controller would collect the post, tags, time stamp and other relevant information, and do a minimal validation of the data. Then it would hand off the processing to a service layer. If the service layer finds an issue, then it should throw an exception which you can then handle in the controller.