86

First of all, I have seen many questions of this, but not enough reasoning behind that. If my question is not good enough and should be removed I'll understand.

I have taken a look at, for example, this and a 45+ voted up answer says he advises you to put the business logic in the model, which sounds pretty logical.

However, my first large project I have done with all my BL fully in the controllers, because I didn't question these things and looked how it is done in the AccountController which is the automatically added if you choose MVC with form authentication. All the methods look pretty stuffed with BL. Or maybe it is the least amount of code that was possible to be added and I am overlooking things?

A person on youtube asked me whether he is right by putting all the logic into his models and at first I was no! Then I started thinking that maybe he was right!?

So, after all, where do I put my business logic? If it is in models classes, then, how much code should be considered a healthy amount in a method which is in controller? One line to call some method from the model in a controller at most and then a return to the view?

Community
  • 1
  • 1
Andrius Naruševičius
  • 8,348
  • 7
  • 49
  • 78
  • 1
    Business logic goes in the controllers. Model logic goes in the Model. Model logic is things that deal with the model specifically/only. Setters/getters/properties/adders/removers, etc. – crush Sep 01 '13 at 21:48
  • 1
    @crush: I don't agree. As I've read - "A model object holds the application's data and "business logic." and "Controller objects ties the model and view objects together." – ChiefTwoPencils Sep 01 '13 at 22:14
  • @BobbyDigital - can you provide a link to the source? :) – Andrius Naruševičius Sep 01 '13 at 22:15
  • Sure, it's in the explanation of proper MVC usage in [The Big Nerd Ranch Guide](http://www.bignerdranch.com/book/android_the_big_nerd_ranch_guide) but unfortunately you'll have to buy the book to confirm this. – ChiefTwoPencils Sep 01 '13 at 22:17
  • I will say though, having just tried to confirm this in a C# book, in asp.net the business logic goes in the middle tier where the top tier would be the UI, middle would be the controller and bottom would be the db. But they aren't speaking specifically/explicitly about MVC. This comes from [C# for Programmers](http://www.deitel.com/Books/C/CSharp2010forProgrammers4e/tabid/3620/Default.aspx) :) – ChiefTwoPencils Sep 01 '13 at 22:24
  • I struggle to see how logic workflows like payments could work in the model... Another business layer option is: http://blog.diatomenterprises.com/asp-net-mvc-business-logic-as-a-separate-layer/ – KCD May 11 '16 at 23:27

12 Answers12

58

I prefer to put domain logic in the model for a couple of reasons.

  1. The model should have no UI code in it and thus be easier to test. Whenever possible, I like to have a fully working (meaning complete test coverage) model before writing any UI code. The controller can trust that the model is doing the right thing and just deal with UI concerns.

  2. If you put domain logic in a controller, it's not as easy to share between different apps, or even between different controllers.

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • 2
    Yes, I really liked the `#2` because I found it hard to share between controllers myself (had to use such methods as static)! – Andrius Naruševičius Sep 01 '13 at 22:13
  • Yes @AndriusNaruševičius, don't do that. You should try and inject your dependencies into controllers and not rely on other controllers. – Mark Walsh Sep 02 '13 at 16:08
  • Note that I think this answer talks about "domain models" (M part of classic MVC patten) which is some what unrelated to ASP.Net MVC "model" (part of MVVM pattern). – Alexei Levenkov Nov 16 '14 at 21:46
  • 1
    So... where do you put logic that relies on multiple models? – Kellen Stuart Apr 02 '20 at 16:17
  • @KolobCanyon - I would most likely create a new model which depended on the other models and put the logic in there. – Ferruccio Apr 03 '20 at 10:36
  • 2
    @Ferrucio That is a bad solution. You end up in a "dependency hell" where you create objects that rely on other objects to be created. It's a bad solution because unnecessary / unused data is passed around for no reason. You want functions to take only what they need to get the job done - otherwise the code becomes unclear very quickly. The better solution is to create business logic classes that take the bare minimum to construct (or even better yet, use dependency injection to get constructed). That way you never end up having to fetch several unrelated object to do the business logic. – Kellen Stuart Apr 03 '20 at 16:32
45

I like to keep my models clean I.e. Just with properties and no business logic. I always think its good to inject dependencies into the controller and these dependencies contain the logic I perform on my models. I like to adhere to the single responsibility principle where possible and I find that models with tons of methods get bloated very quickly. There's pros and cons for both, injecting a lot of dependencies has an overhead yet allows to test in isolation and keeps classes simple and you'll end up having leaner controllers. Despite my logic not actually existing on my model as members of the class, its still business logic. I tend to not have business logic defined in the controller as mocking things like the Httpcontext are a bit of a nightmare and unnecessary.

Mark Walsh
  • 3,241
  • 1
  • 24
  • 46
  • 5
    +1 agree completely. I thought I was the only one who liked to keep models' responsibilities to a minimum! – Lee Feb 24 '14 at 22:27
  • It would be great to see a few little code snippets to get a feel for what you do. What naming convention do you go for when injecting your dependencies? – Luke Sep 25 '14 at 19:47
  • 1
    Sure, he's a gist to my Login Controller https://gist.github.com/markwalsh-liverpool/8fb361a9df0dcf034caf – Mark Walsh Sep 26 '14 at 09:44
  • 1
    So if you don't put your logic in your models or controllers - where do you put it? – niico Mar 09 '17 at 11:58
  • I have injected service classes which contain my business logic. Having all business logic in a model is impractical and your models become huge. You also have to then unit test your models! – Mark Walsh Mar 10 '17 at 15:18
  • 1
    How do you pass arguments to the controller's constructor? Isn't the controller's initialization usually done behind-the-scenes? – Jeff Aug 04 '17 at 14:44
  • 1
    I use dependency injection. – Mark Walsh Aug 05 '17 at 23:11
26

The business logic belongs to the problem domain and everything that belongs to the problem domain goes to the model in MVC.

The controller should be responsible for passing the data from the model to the view and from the view back to the model. The controller is therefore the bridge between what the user interacts with and how the program models and stores the state of the problem. The plumbing, so to speak.

The key here is the distinction between the business logic and the plumbing logic. In my opinion, what the autogenerated Account Controller does is mostly plumbing, not really business logic. Keep in mind that the plumbing logic isn't necessarily short at all, so you don't need to impose artificial limits (like "X number of calls at most in the controller").

Theodoros Chatzigiannakis
  • 28,773
  • 8
  • 68
  • 104
  • 1
    I agree with all this. However, I think a lot of confusion comes from how to structure the classes in the model, esp with EF. IE: do you use partial classes and build out the logic in different C# files? one file for EF and one file for the logic? – S1r-Lanzelot Aug 04 '17 at 19:23
16

There seems to be some confusion around this topic. Mostly it seems that people tend to confuse the MVC pattern with N-tier architecture as an either/or situation. The reality is that the two approaches can be used together, but one is not dependent on the other and neither is required.

N-tier architecture is concerned with separating an application into multiple tiers. A simple example is where the application is split into a presentation layer, a business logic layer, and a data access layer.

MVC is a design pattern dealing with the presentation layer of an application. It is entirely possible to design an application following an MVC approach without separating business logic and data access logic from the presentation layer and thus end up with a single tier design.

The result, if you are following an MVC approach without also separating the application into tiers is that you end up with Models, Views, and Controllers that have bits of business rules and data access logic mixed in with the rest of the logic.

By definition, in an N-tier architecture, the presentation tier is only supposed to be able to communicate with the business logic layer so it should hold that any of the MVC components can only communicate with the business logic layer.

If you are building an application that does not involve presentation, and thus not a presentation layer, you should not have to concern yourself with the MVC pattern. However, you very well may still split your application into multiple tiers and thus follow an N-tier design even though there is no presentation layer involved.

treefiddy
  • 541
  • 6
  • 5
13

My team when moved to mvc from webforms (asp.net) did alot of research and came up with the following structure. According to me its not about how big or small the application is. Its about keeping the code clean and clear.

DALProject

AccountsDAL.cs --- > Calls SP or any ORM if ur using any

BLLProject

AccountsBLL.cs ---> Calls DAL

WebProject

Model
    AccountsModel --- > Contains properties And call BLL
Controllers
    IndexController ---> Calls Models and returns View
Views
    Index

Controllers should be responsible for the data passing between model and view. Other than that it there should not be any unnecessary code. For example if you are logging it should be done at model level rather than controller.

Muneeb Zulfiqar
  • 1,003
  • 2
  • 13
  • 31
10

The business logic should not go in your Models Views or Controllers. There should be a separate Business Logic Layer ; the sole purpose of this layer is to handle your business logic. This is more in-line with SOLID.

If you were to put your business logic in M V or C, you end up with code that is difficult to test / reuse.

What about putting the logic in the Models?

That is a bad solution.

You will end up in a Dependency Hell where objects rely on objects. enter image description here

Even if you have a dead simple function, you'll still have to satisfy all the dependencies to call it.

It will also cause unnecessary and unused data to be passed around for no reason. This could also affect performance depending on how bad it gets.

I should also mention that unit testing becomes a pain in the a** because you have to mock multiple objects just to test a simple function.

Principles of Clean Code Applicable

  1. Classes / Functions take only what they need to get the job done.
  2. Functions should take 3 parameters or less if possible
  3. Name classes / functions / variables intelligently (follow Microsoft's standards)
  4. Do not couple business logic to Model View or Controller

Controllers

In your controller, you should be able to use dependency injection to inject the business logic layer. Make sure you controller is only used to route information to the business logic layer. The controller should NOT have business logic directly in it. Any validation needs to be handled by IValidatable on the Model. Any business logic needs to be routed to a separate layer.

Kellen Stuart
  • 7,775
  • 7
  • 59
  • 82
  • Here where I work we have a business layer and I only wanted that we didn't have it. Business layers are pure mess, logic are supposed to be in model. – Mateus Felipe Apr 23 '20 at 13:01
  • @MateusFelipe So, where do you put logic that requires multiple models (for example: Payment and Product)? Do you create a new model that has `Payment` and `Product` as an instance variable? What do you name that object? If a model is not used in a view, it is no longer a model. It is part of a separate layer. Ideally, that class you make should only take what it needs from Payment and Product to get it's job done. If it only needs the `productName` and the `price`, it should only take those two parameters, not the entire object. – Kellen Stuart Apr 23 '20 at 18:16
  • The M in MVC has traditionally referred to "Application Model" which is just a simple way of saying 'the entire rest of the application", but that's not really helpful unless you understand the rest. The V in MVC traditionally refers to what the user is viewing, sometimes that view is modeled in a "ViewModel" class, but that still means it's architecturally a part of the View. C is the Controller and refers to anything in your code base that controls traffic between requests for app logic and viewing the results. "Multiple Models" exposes a fundamental misunderstanding of what MVC is. – WhiteleyJ Apr 12 '21 at 18:45
9

Generally speaking, business logic shouldn't reside in any of the MVC players; it should only be consumed by your controller actions.

As many have mentioned, it's best to create a library to host business logic as a set of client agnostic, reusable components.

When done this way, we greatly increase reusability, compatibility, scalability, and testability with our software. We also reduce our dependence on certain framework features, which makes it easier to migrate to newer / different technologies.

Abstracting our business logic into a stand alone assembly (or assemblies) has served us well over the years. Our business logic can then be consumed by virtually any .NET technology (ASP.NET MVC/API/Core, WPF, Win Forms, WCF, UWP, WF, Console, etc.).

In addition, we like our middle tier to handle business rule and validation logic to reduce our dependencies on the .NET MVC Framework's. For example, we avoid using the .NET MVCs validation helpers and instead rely on our own. This is another factor that allows us to easily consume our business logic from any .NET technology.

Logically designing our middle tier this way has allowed us to easily achieve this physical architecture:

enter image description here

It was written with Peasy.NET, and has served us well over the years. So well in fact that we decided to open source it.

If anyone is curious as to what our middle tier looks like, here is a sample of a client agnostic, business layer. It also showcases the consumption of it by multiple .NET clients (ASP.NET MVC, Web Api, and WPF).

Hope this helps someone!

ahanusa
  • 969
  • 1
  • 9
  • 11
  • Mostly there's no need to re-use the logic. If I let's say decide to use ASP.NET Core MVC for Web API, I will never want to use that business logic in WPF or WinForms. Because the client will communicate with the server anyway. Putting business logic and especially database access logic on the client-side is just bad. – Konrad Aug 17 '18 at 12:05
  • The more tiers you add I'd say it decreases maintainability and testability. In the end integration tests matter more. – Konrad Aug 17 '18 at 12:07
5

The general answer I have is that business logic normally fits into two categories:

Object Oriented Business Logic: Gets modeled as objects (in the model), usually injected as repositories.

Procedural Business Logic: Goes in a service with an interface that can be injected into a controller.

Controller Logic: Logic that controls how commands are received and passed to the models/services, then how those results are passed to the view.

Controllers should have no business logic, it's a very specific part of a design pattern for controlling how a user interface passes input off to the models that handle business logic (or services if your problems are more procedural in nature).

WhiteleyJ
  • 1,393
  • 1
  • 22
  • 29
2

I like to keep my models clean as well (ref: @Mark Walsh). The problem of not being able to reuse logic embedded in controllers can easily be overcome through dependency injection, or, if you think there would be too much of that, expose your business/domain logic through interfaces and use the façade pattern in the controllers. That way you get the functionality you need, but keep both the controllers and model nice and clean.

Bob H
  • 47
  • 6
1

I would also prefer to keep models clean. The MVC controllers should be used only to make calls and should also be kept clean. So depending upon its reusability, sensitivity and relevance the business logic can be written in

1.WebApi Controller: The advantage of using a webapi controller is that you can expose these as services later to other devices making your code reuseable.

2. BAL / Common commonent: There are some logics which have specific usage and cannot be exposed as an api, can be pushed in this class.

3. Repository: All the database related queries are added in a repository. There can be a generic repository which will implement all the functions (CRUD operations)or specific repositories for each table. Depending upon the operations to be performed.

Nikitesh
  • 1,287
  • 1
  • 17
  • 38
1

As ahanusa wrote, you should put your business logics into separate DLL or separate directory.
I often use a directory named Logics at same level of Models and Controllers where I put classes which do business logics.
In this way I let both models and controllers clean.

Ryozzo
  • 92
  • 8
0

I know that it's a question about MVC, but I think the example I'm giving (Web API) will be usefull.

I'm developing my first Web API and I'm re-using the business logic from other applications. To be specific, it comes from an external DLL, so my API is used just to "talk" with a SAP solution, receiving requests from PO and send responses back.

How could I put my logic (already implemented) into my controller? I don't need it. My controller will only receive, validate requests and compose responses to send data back.

I'm working with ViewModel classes and all they must have is a mapping function, just to read information from TransferObjects (that comes from the external DLL) and translate to a ViewModel.

I'm not comfortable with my application (in this case Web API) holding the business logic, I think that the re-usability will be lost in this way.

I'm treating my business logic as a dependency that I inject into controller.

I've done a lot of refactoring in the legacy to provide a Unit Testable solution, I had to create a lot of interfaces and implement some design patterns into the legacy to provide this solution.

In my point of view, the business layer must be apart of the application, preferably in another class library. So you will have a real separation concept implemented in your application.

Of course, if your CORE (business) is your application (API/WebSite), the business rules will be implemented into your MVC classes. But in the future if you want to develop a new app and some business rules are the same, I bet you will have a lot of problems just to maintain the same logic implemented in both applications.

BSOD
  • 31
  • 7