101

Derik Whitaker posted an article a couple of days ago that hit a point that I've been curious about for some time: should business logic exist in controllers?

So far all the ASP.NET MVC demos I've seen put repository access and business logic in the controller. Some even throw validation in there as well. This results in fairly large, bloated controllers. Is this really the way to use the MVC framework? It seems that this is just going to end up with a lot of duplicated code and logic spread out across different controllers.

Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
Kevin Pang
  • 41,172
  • 38
  • 121
  • 173
  • The link to the article is dead - http://web.archive.org/web/20150906064521/http://devlicio.us/blogs/derik_whittaker/archive/2008/10/22/how-is-interacting-with-your-data-repository-in-your-controller-different-or-better-than-doing-it-in-your-code-behind.aspx is a copy from archive.org for anyone else interested. – Stuart Moore May 22 '17 at 10:07

6 Answers6

75

Business logic should really be in the model. You should be aiming for fat models, skinny controllers.

For example, instead of having:

public interface IOrderService{
    int CalculateTotal(Order order);
}

I would rather have:

public class Order{
    int CalculateTotal(ITaxService service){...}        
}

This assumes that tax is calculate by an external service, and requires your model to know about interfaces to your external services.

This would make your controller look something like:

public class OrdersController{
    public OrdersController(ITaxService taxService, IOrdersRepository ordersRepository){...}

    public void Show(int id){
        ViewData["OrderTotal"] = ordersRepository.LoadOrder(id).CalculateTotal(taxService);
    }
}

Or something like that.

jonnii
  • 28,019
  • 8
  • 80
  • 108
  • 1
    So would you inject Services into your controllers instead of repositories then? How does the Unit of Work principle come into play in that case? – Kevin Pang Oct 24 '08 at 21:01
  • I wrote some more stuff, I hope this makes more sense. You might want to also read: http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model Even though it's about Rails it's still very much applicable. – jonnii Oct 24 '08 at 21:12
  • I would call a repository a service, personally. – Brad Wilson Oct 25 '08 at 00:49
  • They're definitely a kind of service, but are specifically for data access. It's just a convention I use, not something I advocate specifically. – jonnii Oct 25 '08 at 22:35
  • This is an old answer but something stuck into my mind. The CalculateTotal method on Model uses ITaxService the get the job done. So in that case, is not the actual business logic by service rather than model itself ? – emre nevayeshirazi Feb 01 '13 at 22:07
  • I was thinking that the CalculateTotal() method would do something with the result of the tax service. For example it would sum the order items, apply discounts then calculate a tax for the order's address state. – jonnii Feb 01 '13 at 22:12
  • The solution by AlejandroR is a better one. The structure should be like Controller -> Business Service -> Unit of Work -> Data Repository -> Entity Framework – Yashvit Aug 26 '13 at 13:22
  • I disagree, I consider the repository pattern an antipattern. You can get away with collapsing your business service into the model, and just using the unit of work directly. – jonnii Aug 27 '13 at 01:01
  • What is wrong with having an interface for your services? Should you really be accessing your domain objects in your controllers? – Luke Mar 30 '15 at 13:09
  • 2
    This will make your model tight coupled with ITaxService. If you want to reuse model in another project or other dll, you have to have ITaxService implementation or reference, otherwise your model will be broken, that results in violation of SOLID principles. ITaxService should have a reference of your model. With this way, you can reuse your model in other project without need of ITaxService reference. – Mehmet Ali Sert Feb 21 '16 at 22:53
  • I think, what you guys did not take into account, is the fact that there is a difference between a CRUD application and riche domain application. Straight, plaine old, MVC is usually used in CRUD application. Since MVC is difficult to maintain and is hard to make evolve where the domain is big and contains multiple business rules (riche domain), it has to be adapted to something like @AlejandroR answer. So in summary both answers are correct it depends only if your doing CRUD or riche domain. – Sebastien Nov 22 '16 at 20:52
67

I like the diagram presented by Microsoft Patterns & Practices. And I believe in the adage 'A picture is worth a thousand words'.

Diagram shows architecture of MVC and business sevices layers

Christian Phillips
  • 18,399
  • 8
  • 53
  • 82
AlejandroR
  • 5,133
  • 4
  • 35
  • 45
  • 7
    That's really useful! Could you tell me where on that site you found this diagram? – Rob Church Mar 08 '13 at 11:16
  • 2
    This is from Microsoft's 'Server-Side Implementation' http://msdn.microsoft.com/en-us/library/hh404093.aspx – Justin Jun 16 '14 at 07:36
  • OK but in, say, an MVC app - where does the business logic go? Seems we need an additoinal service layer or something?! – niico Mar 09 '17 at 12:03
14

This is a fascinating question.

I think that its interesting that a large number of sample MVC applications actually fail to follow the MVC paradigm in the sense of truly placing the "business logic" entirely in the model. Martin Fowler has pointed out that MVC is not a pattern in the sense of the Gang Of Four. Rather, it is paradigm that the programmer must add patterns to if they are creating something beyond a toy app.

So, the short answer is that "business logic" should indeed not live in the controller, since the controller has the added function of dealing with the view and user interactions and we want to create objects with only one purpose.

A longer answer is that you need to put some thought into the design of your model layer before just moving logic from controller to model. Perhaps you can handle all of app logic using REST, in which case the model's design should be fairly clear. If not, you should know what approach you are going to use to keep your model from becoming bloated.

Chris
  • 6,272
  • 9
  • 35
  • 57
Joe Soul-bringer
  • 3,294
  • 5
  • 31
  • 37
14

You can check this awesome tutorial by Stephen Walther that shows Validating with a Service Layer.

Learn how to move your validation logic out of your controller actions and into a separate service layer. In this tutorial, Stephen Walther explains how you can maintain a sharp separation of concerns by isolating your service layer from your controller layer.

Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
  • 2
    This is the most correct answer. I personally further advocate not exposing services to the controller, choosing instead to use a ViewModel concept such as is found in the MVVM pattern. Imagine a scenario where you want to write a business app with a desktop interface (say, windows forms or WPF) and also a web interface. Solving that problem leads you to the "skinny controller" pattern as is advocated here also. Bottom line: never put business logic in a model or a controller and don't put anything in a controller that you don't have too. –  Sep 26 '15 at 15:56
9

Business Logic should not be contained in controllers. Controllers should be as skinny as possible, ideally follow the patter:

  1. Find domain entity
  2. Act on domain entity
  3. Prepare data for view / return results

Additionally controllers can contain some application logic.

So where do I put my business logic? In Model.

What is Model? Now that's a good question. Please see Microsoft Patterns and Practices article (kudos to AlejandroR for excellent find). In here there are three categories of models:

  • View Model: This is simply a data bag, with minimal, if any, logic to pass data from and to views, contains basic field validation.
  • Domain Model: Fat model with business logic, operates on a single or multiple data entities (i.e. entity A in a given state than action on entity B)
  • Data Model: Storage-aware model, logic contained within a single entity relates only to that entity (i.e. if field a then field b)

Of course, MVC is a paradigm that comes in different varieties. What I describe here is MVC occupying top layer only, vide this article on Wikipedia

Today, MVC and similar model-view-presenter (MVP) are Separation of Concerns design patterns that apply exclusively to the presentation layer of a larger system. In simple scenarios MVC may represent the primary design of a system, reaching directly into the database; however, in most scenarios the Controller and Model in MVC have a loose dependency on either a Service or Data layer/tier. This is all about Client-Server architecture

Jacek Glen
  • 1,506
  • 12
  • 14
-1

If u use Dependency Injectors your business logic will go to them and hence you will get neat and clean controllers.

chandresh patel
  • 309
  • 1
  • 10