Introduction
In this article, we will explore Clean Architecture in a practical way. Clean architecture is a software design approach that ensures your application's code remains organized, maintainable, and adaptable to change. Its core principle is to separate the business logic from external dependencies like frameworks and user interfaces, allowing for easier updates and scalability without affecting the core system.
The main goal of clean architecture is to create a structure where business logic is isolated, reducing the risk of changes impacting the core system. This means you can replace or modify frameworks, databases, or UI components without rewriting your core code. By keeping dependencies external and replaceable, you create a flexible, long-lasting application architecture that stands the test of time.
This article will guide you through implementing Clean Architecture in .NET Core 8 step by step, ensuring that your application is built on solid, scalable principles.
What is Clean Architecture?
Clean Architecture is a software design pattern that organizes code into distinct layers, ensuring a clear separation of concerns. Its main goal is to make applications more maintainable, testable, and adaptable to change. The architecture isolates the core business logic from external dependencies like databases, frameworks, and user interfaces.
In Clean Architecture, the code is divided into four key layers.
- Domain Layer: Contains the core business logic and entities. This layer is completely independent of external technologies.
- Application Layer: Manages use cases and interacts with the Domain Layer to perform business operations.
- Infrastructure Layer: Handles external concerns such as databases, APIs, and file systems. It implements repository patterns to separate data access logic.
- Presentation Layer: The UI or API layer that interacts with the users or other systems. It handles HTTP requests and responses in the case of a Web API.
By keeping these layers independent, Clean Architecture ensures that changes to the UI, database, or any external service won't affect the core logic of the application, making it more resilient and flexible in the long run.
Advantages & Disadvantages of Clean Architecture
Advantages |
Disadvantages |
Clear Organization: Each part of the app has a specific role. |
Complex Setup: Harder to set up for small projects. |
Easy to Maintain: Changes can be made without affecting the whole system. |
Takes More Time: Slower to develop initially. |
Better Testing: Core logic is easier to test. |
Harder to Learn: This can be confusing for new developers. |
Flexible: You can replace databases, UI, or frameworks without changing core logic. |
Too Complex for Small Apps: May be too much for simple projects. |
No Framework Lock-in: The core logic doesn’t depend on specific frameworks. |
More Code: Adds extra code and files to the project. |
Easier Collaboration: Developers can work on different parts separately. |
May Slow Performance: Extra layers might affect speed. |
Scalable: Easy to add new features as the app grows. |
Repeated Code: This can lead to similar code across layers. |
Future-Proof: Technology changes won’t break the core. |
Harder to Debug: Debugging can be tricky with many layers. |
Implementation of Clean Architecture
Now, we can see our project structure as shown in the picture above.
Step 1. Configure a new project with a blank solution.
We are now going to implement Clean Architecture. First, create a project with a blank solution in Visual Studio and name it CleanArchitectureDemo.
Step 2. Create a new Class Library project with the Name CleanArchitecture.Domain.
Domain Layer
The Domain Layer in Clean Architecture contains enterprise logic, including entities and their specifications. This layer is at the center of the architecture and includes application entities, which represent the application model classes or database model classes.
Step 3. Next, we will add a new item to this project: a model class named Movie.cs.
Step 4. Code of Movie.cs model class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CleanArchitecture.Domain
{
public class Movie
{
public Movie()
{
}
public Movie(int MovieId,string Name,int Cost) {
this.MovieId = MovieId;
this.Name = Name;
this.Cost = Cost;
}
public int MovieId { get; set; }
public string Name { get; set; } = string.Empty;
public int Cost { get; set; }
}
}
Application Layer
The Application Layer contains the business logic. All business logic is written in this layer, and service interfaces are kept separate from their implementations to promote loose coupling and separation of concerns.
Now, we will work on the Application Layer. We will follow the same process as we did for the Domain Layer. Please add a library project and name it CleanArchitectureDemo.Application.
Step 5. We need to create three folders named.
- IService
- Service
- IRepository
These folders will include the following files respectively.
- IMovieService.cs in the IService folder
- MovieService.cs in the Service folder
- IMovieRepository.cs in the IRepository folder.
Step 7. However, we need to add the project reference of the Domain Layer in the Application Layer. Right-click on the project, click on the 'Add' button, and then select 'Project Reference' to add the reference in the Application Layer.
Click the OK button. After that, our project reference will be added to our system.
Step 8. Code of IMovieService.cs Interface.
using CleanArchitecture.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CleanArchitecture.Application.IService
{
public interface IMovieService
{
List<Movie> GetAllMovies();
}
}
Step 9. Code of MovieService.cs Class.
using CleanArchitecture.Application.IRepository;
using CleanArchitecture.Application.IService;
using CleanArchitecture.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CleanArchitecture.Application.Service
{
public class MovieService : IMovieService
{
private readonly IMovieRepository movieRepository;
public MovieService(IMovieRepository _movieRepository) {
movieRepository = _movieRepository;
}
public List<Movie> GetAllMovies()
{
var movies= movieRepository.GetAllMovies();
return movies;
}
}
}
Step 10. Code of IMovieRepository.cs Interface.
using CleanArchitecture.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CleanArchitecture.Application.IRepository
{
public interface IMovieRepository
{
List<Movie> GetAllMovies();
}
}
Infrastructure Layer
We need to handle external concerns such as databases, APIs, and file systems. The database logic will be written here, implementing the repository pattern to separate data access logic
Now, we will work on the Infrastructure Layer. We will follow the same process as we did for the Application Layer. Please add a library project and name it CleanArchitectureDemo.Infrastructure.
Step 11. We need to create a folder named Repository. This folder will include the file MovieRepository.cs.
Step 12. However, we need to add the project reference of the Application Layer in the Infrastructure Layer. Right-click on the project, click on the 'Add' button and then select 'Project Reference' to add the reference in the Infrastructure Layer.
Click the OK button. After that, our project reference will be added to our system.
Step 13. Code of MovieRepository.cs Class.
using CleanArchitecture.Application.IRepository;
using CleanArchitecture.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CleanArchitecture.Infrastructure.Repository
{
public class MovieRepository : IMovieRepository
{
private static List<Movie> movies = new List<Movie>()
{
new Movie() { Cost=100,Name="M1",MovieId=1},
new Movie() { Cost=200,Name="M2",MovieId=2},
new Movie() { Cost=150,Name="M3",MovieId=3},
};
public List<Movie> GetAllMovies()
{
return movies;
}
}
}
Presentation Layer
The Presentation Layer is the final layer, responsible for presenting data to the front-end user for every HTTP request.
We need to add an API project to present data for HTTP requests. The main project will be named CleanArchitecture.API and this project will communicate with the application layer to invoke service dependencies.
Step 14. However, we need to add the project reference of the Infrastructure Layer & Application Layer in the Presentation Layer. Right-click on the project, click on the 'Add' button and then select 'Project Reference' to add the reference in the Presentation Layer.
Click the OK button. After that, our project reference will be added to our system.
Step 15. Now we Add Dependency Injection In the Program.cs File.
using CleanArchitecture.Application.IRepository;
using CleanArchitecture.Application.IService;
using CleanArchitecture.Application.Service;
using CleanArchitecture.Infrastructure.Repository;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddScoped<IMovieRepository, MovieRepository>();
builder.Services.AddScoped<IMovieService, MovieService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
- Add a New Controller
- Right-click on the Controllers folder.
- Select Add > New Item.
- Choose Controller Template
- In the "Add New Item" dialog, select ASP.NET Core from the left pane.
- Then choose Controller Class from the options.
- Name the new file MovieController.cs.
Step 16. Code of MovieController.cs Class.
using CleanArchitecture.Application.IService;
using Microsoft.AspNetCore.Mvc;
namespace CleanArchitecture.API.Controllers
{
[Route("api/[controller]")]
public class MovieController : Controller
{
private readonly IMovieService _movieService;
public MovieController(IMovieService movieService)
{
_movieService = movieService;
}
[HttpGet("Get")]
public IActionResult GetMovies()
{
var movieList = _movieService.GetAllMovies();
return Ok(movieList);
}
}
}
Output
Conclusion
In this article, we implemented Clean Architecture using .NET Core 8.0 by following a straightforward approach. Now we understand how the layers communicate with each other in Clean Architecture. We can develop our projects using Clean Architecture for Web API or MVC-based projects to achieve our goals.