Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best place for business logic in ASP.NET MVC when using repositories?

When implementing Repository for database in ASP.NET MVC project, is it correct to place business logic into it or may be better to place logic in controller class? Or use additional service and helper classes for manipulating data?

like image 802
Alexander Avatar asked Oct 15 '11 12:10

Alexander


People also ask

Where do you put business logic in MVC?

The business logic should be placed in the model, and we should be aiming for fat models and skinny controllers. As a start point, we should start from the controller logic. For example: on update, your controller should direct your code to the method/service that delivers your changes to the model.

Where do you usually put your business logic?

The Right Answer Is… Business logic should live in the data model. And, what's more, it should live in the graph data model because that's the right abstraction for the next twenty years.

Should business logic go in controller?

For non trivial applications, business logic/business rules/data access should not be placed directly into Models, Views, or Controllers. To do so would be placing business logic in your presentation layer and thus reducing reuse and maintainability of your code.

What is the right way to include a repository into a controller?

By taking advantage of dependency injection (DI), repositories can be injected into a controller's constructor. the following diagram shows the relationship between the repository and Entity Framework data context, in which MVC controllers interact with the repository rather than directly with Entity Framework.


1 Answers

Ultimately there isn't a perfect place for your business logic besides its own layer (as part of the "Model" layer). Often you can get away with a different implementation, but there are trade offs in every case.

The trade off to creating another layer for the business logic is that you have to actually encapsulate your code. If you're too aggressive, you might also get some duplication between your entities and your domain model (if your DB's relational semantics already take care of your buiness logic).

View

The view is the most brittle part of your app, as it is the most likely part to change.

It is also very hard to get business logic correct in your view, due to having to support all the various view state transitions.

It is extremely well known these days that you just don't do this :)

Repository

The issue here is one of maintenance and purity of abstraction. Violating this can confuse people and make your app hard to maintain.

From the P of EAA article on the Repository pattern:

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection

A repository is an abstraction that presents your data storage as a collection that holds domain objects.

No domain logic should reside in it. Instead, it should exist in your domain objects (by definition, as your business logic is your domain).

To do otherwise (to make your repository do double duty and also validate domain logic) would be a violation of SRP (Single Responsibility Principle), and would be a code smell.

You can have higher level domain objects that work with collections of domain objects to validate domain logic (such as dependencies within a collection of objects, size limits, etc). They will still use your repositories under the covers to do final storage/retrieval of domain objects, so they won't be doing double duty (so won't violate SRP).

Controller

The controller is also not a good place to put business logic. The controller's job is to mediate between the controller and the model.

The model is the domain, and the domain is your business logic.

Entities

You might consider putting domain data in entities.

But you must be careful when accessing navigation properties if the entities are attached, as you can trigger inadvertent DB queries or exceptions (depending on if your context is disposed or not). Detaching them is also a problem, as it destroys your object graph unless you explicitly reattach the objects to each other after detaching them from the context.

If you make separate domain model classes, you might consider treating entities as DTOs only.

Edit: IValidatableObject

I found out just now about a feature in Entity Framework 4.1 that you may want to check out: the IValidatableObject interface.

You can make your entities partial classes, and in the partial class, implement this interface. When you do, the Entity Framework will call Validate on save, and you can call Validate whenever it makes sense for you to do so.

This might help you avoid splitting your persistence model from your domain model in additional cases.

See this article: http://msdn.microsoft.com/en-us/data/gg193959

Side note: Views/View Models

In case you are thinking about it, I suggest you avoid the temptation to pass entities back to the view. It will break in a lot of cases (e.g. Javascript serialization to store view state), and cause unintentional DB queries in other cases. Pass back simple types instead (strings, ints, lists, hashsets, dictionaries, etc), or construct view model classes to pass to the view.

like image 130
Merlyn Morgan-Graham Avatar answered Oct 09 '22 07:10

Merlyn Morgan-Graham