Comments

Layered Architecture in ASP.NET Core Applications

One of the viewers of my YouTube channel asked me an interesting question. He mentioned in a typical layered architecture, he sees ASP.NET MVC building blocks (Controller, View, and Model) as part of the presentation layer. These days, however, a lot of modern applications are built with Angular/React on the client and ASP.NET Core (Web API) on the server. So, what is the presentation layer in this kind of architecture? Let’s see!

With this stack, we have the following layers:

  • Presentation
  • Service
  • Business Logic/Application Core
  • Data Access/Persistence

Presentation Layer

Your Angular components, their templates, and the models you define in your Angular app are all presentation layer artifacts.

Service Layer

The confusing thing about this layer is that the term “service” is overloaded and it means different things to different people. In the context of a layered architecture, it wraps an application and exposes the application functionality in terms of a simple API that the user interface can talk to. This is the classic definition. Think of it as the glue between the presentation and business logic layers.

Now, in our modern stack, our logical service layer is physically composed of two parts: one part is on the client (Angular HTTP services) and the other part is on the server (ASP.NET Core controllers). These Angular services and ASP.NET Core controllers are very cohesive. The methods on these services (eg CourseService.getCourses()) talk directly to the endpoints exposed by your ASP.NET Core controllers.

Business Logic Layer

In your ASP.NET Core controllers, you often use repository interfaces (ICourseRepository), domain classes (Course) and services (PhotoService). All these are part of the business logic layer. They represent the core of an application irrespective of any presentation or persistence frameworks.

Note that here I’m talking about repository interfaces and not their implementations. These implementations are part of the data access/persistence layer.

Also, note that the services we have here are responsible for orchestration. For example, when adding a photo to a course, first, you need to store that photo in the file system (or some other kind of storage), and then you need to add it to the database (using a repository interface). Here is an example:

// Store the file first 
var uploadsPath = Path.Combine(host.WebRoot, "uploads");
if (!Directory.Exists(uploadsPath))
    Directory.CreateDirectory(uploadsPath);

var fileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName);
var filePath = Path.Combine(uploadsPath, fileName);

using (var stream = new FileStream(filePath, FileMode.Create))
{  
    file.Copyto(stream);
}

// Add a record to the database
var photo = new Photo { FileName = fileName };
repository.Add(photo);
unitOfWork.Complete(); 

You wouldn’t write all this logic inside an ASP.NET Core Controller. Imagine, tomorrow you decide to use a different framework. You want to re-use as much code as possible. By encapsulating this code in a service (PhotoService.AddPhoto()), you can switch from ASP.NET Core to a different framework with less effort.

But wait for a second…

Now, that strongly-opinionated developer comes and says: “But who does replace ASP.NET Core with something else? How often does that happen?” Let’s say never! By moving all this logic from a controller into a service, you put the responsibility where it really belongs. The result is cleaner, slimmer, easier to read and easier to test controllers.

Imagine a restaurant where the chef does it all. He’s at the door, welcoming guests, giving them a table, taking their order, then going in the kitchen, chopping the vegetables, cooking, washing the dishes, then coming out and giving the bill to the guests. Would you go to that restaurant? I hope not!

In a good and organized restaurant, there are a few people each focusing on only one job. The waiters/waitresses are purely responsible for welcoming the guests and giving them the bill. The chef is purely responsible for cooking. He or she doesn’t wash the dishes! By the same token, you should have classes that do only one thing and do it well. This is what we call separation of concerns. You should put the responsibility where it really belongs, even if you’re never going to change the presentation or persistence framework of your application.

So, once again, all your domain classes (Course), repository interfaces (ICourseRepository) and application services (PhotoService) are part of the business logic layer. They represent the core of your application completely decoupled from any presentation and persistence frameworks. This is what Uncle Bob defines as Clean Architecture.

Data Access Layer

This layer is all about persistence. Here we have implementations tightly coupled to Entity Framework (or other frameworks) for persisting and retrieving data. If you’re using Entity Framework, your DbContext belongs in this layer. So do UnitofWork and Repository implementations.

Splitting a Project

Now, a common (and bad) practice I’ve seen some developers do, is that they blindly split an ASP.NET project into multiple class libraries, one for each layer. And with this, they assume just because they have a class library called MyProject.BLL or MyProject.DAL, they have properly layered their application. But that’s not necessarily right.

What matters is the direction of dependency and coupling between classes, not folders or projects. You can easily organize your classes into folders and projects but these classes can be poorly coupled to each other, which results in spaghetti architecture. Read my blog post on the topic:

Should you split your ASP.NET MVC/Core projects?

 

If you learned something from this post, please share it and drop your comments/questions below.

Hi! My name is Mosh Hamedani. I’m a software engineer with two decades of experience and I’ve taught over three million people how to code or how to become professional software engineers through my YouTube channel and online courses. It’s my mission to make software engineering accessible to everyone.
Tags: , , , , ,

11 responses to “Layered Architecture in ASP.NET Core Applications”

  1. Ganapati Panapana says:

    nice one mosh !! Keep on posting !!! fan of your articles !!!

  2. Petar Stoyanov says:

    Nice Article. I wonder what do you think of the Clean architecture(Uncle Bob) ideas and if you have implemented something like that in a web project ?

  3. Billy Shelton says:

    LOL. Just couldn’t resist. One of the best restaurants I have ever been to had 4 tables and the chef. He came out greeted you, described the 3-4 dishes on the menu for the evening then went back and cooked. Absolutely amazing food. But he didn’t stay in business long. Your point is well taken, that doesn’t scale well.

  4. Nehmia says:

    Just one thought. If I am not mistaken, on your post I see that the business logic is inside a domain service class instead of a domain model. On one of your architecture videos, I remember your strong opinion against anemic domain models and that business logic should always reside in models.

    The ‘PhoneService’ is in your business logic layer which makes sense to put your logic there but what about your domain models? Wouldn’t they become anemic? Just a thought.

    • Suraj Yadav says:

      I think we are having a service in business logic which deals with actual implementation.
      And we got a service layer for coupling the business layer with UI – this service layer consists of controllers (WebAPI) and shouldn’t have the services mentioned in DDD pattern as those are actual services for the models and not for any coupling type in some technology. 😀 just thinking. But, if i am not wrong with these words so far, we are having (oh man, why? ) double services layers , one for technological (controller) dependancy and one for model (photo servier) dependancy

  5. Ethyl says:

    Hi,

    I’ve tried store my Repository interfaces inside the BusinessLogicLayer then the implementation is stored in my DataAccessLayer because you’ve mentioned that Interfaces are part of business logic. The problem that I’m facing says, “A reference to ‘BusinessLogicLayer’ could not be added. Adding this project as a reference would cause a circular dependency”

    • Hi Ethyl,

      I believe you are getting this error because you are not using DI. Dependency Injection will allow your Business Logic project work with the interfaces only and the implementations will be resolved and instantiated by DI containers. There should not be any direct reference required from BL assembly to DAL assembly. Another suggestion, separate assembly for BL and DAL works good only for pretty large projects with lots of classes. They are not much worth unless they serve specific business needs like –

      1. Each assembly can be deployed on separate tiers (physical servers)
      2. Each assembly is owned by a separate team with limited inter-communication and contract definition becomes imoprtant
      3. Each assembly is developed using a different tech stack

      I used to create different assemblies earlier, but now have resorted to different folders in same project. This gives me ease of use, freedom from circular reference and improved build time (due to lesser assemblies).

      Hope this helps!!

  6. Shahnawaz says:

    My question is I have AdminDB.Access project for sellerAdmin and WebDB.Access Project for BuyerWebsite were Repository is available in AdminDB.Access project, so can i use AdminDB.Access project for for both seller and buyer website or should i use separate DbAccess, what will be impact

  7. derily says:

    how to manage transaction when use multiple repository in one service

  8. Thanks again Mosh, I finished my few projects 2 years ago with this layered architecture ..its awesome results gave me..clean code, easy to debug, visible business logic. I am a keen fan about your teaching..and it really helped me to achieve my tech career.

  9. Taj says:

    Great article Mosh. Keep posting please.

Leave a Reply

Connect with Me
  • Categories
  • Popular Posts

    %d bloggers like this: