Clean Architecture with ASP.Net Core: An Overview
In the case of any development, Good Architecture is one of the significant aspects of developing modular, scalable, and maintainable applications. Different types of architectural design may vary as per their details. But one common thing in all architectural design, i.e., Separation of Concern. We can achieve this Separation of Concern concept by splitting the entire application into multiple layers.
Clean Architecture is a software architecture pattern through which we can keep the code under control without any tidiness. The central concept behind the Clean Architecture in any application is to write down the code without any dependency that is unlikely to change. So, in this way, if we change the Framework version, database, or UI-related code, the Core of the application (Business Rules / Domain) does not require change. It means in the application if we use any external dependency that is replaceable without making any code changes in the core system.
To make things easier for you, Dot Net Tricks brings a comprehensive skill-oriented ASP.NET Core Certification.
Overview of Clean Architecture
1. The Core Layer
The Core Layer is made up of two parts, the inner core and the outer core. The inner core is the domain and the outer core is the application. This consists of two projects in the solution under the Core folder, the Application and the Domain projects.
1. Inner Core (Domain Layer)
This layer contains application-independent business logic. This is the part of the business logic that would be the same even if we weren’t building software. It is a formulation of the core business rules.
The organization of this project follows Domain-Driven design patterns, although this is a matter of preference and can be handled any way you see fit. This includes:
- Aggregates, entities, value objects, custom domain exceptions, and interfaces for domain services.
- Interfaces for domain-driven design concepts (i.e. IAggregateRoot, IDomainEvent, IEntity).
- Base implementations of aggregate root and domain events. Also contains specific domain events about the business processes.
2. Outer Core (Application Layer)
This layer contains application-specific business logic. This contains the “what” the system should do. This includes:
- Interfaces for infrastructure components such as repositories, unit-of-work, and event sourcing.
- Commands and Queries models and handlers
- Interfaces and DTOs for cross-cutting concerns (i.e. service bus)
- Authorization operations, requirements, and handlers implementations
- Interfaces and concrete implementations of application-specific business logic services.
- Mapping profiles between domain entities and CQRS models.
2. The Infrastructure Layer
This layer contains details, concrete implementations for repositories, unit-of-work, event stores, service bus implementations, etc. This contains the “how” the system should do what is supposed to do. The decoupling between the application layer and the infrastructure layer is what allows solution structures like this one to change and/or add specific implementations as the project requirements change.
In overview, this layer contains:
- Generic and specific repository implementations
- EF DbContexts, data models, and migrations
- Event sourcing persistence and service implementations
- Implementations for cross-cutting concerns (i.e., application configuration service, localization service, etc.)
- Data entity auditing implementation
3. The Presentation Layer
This layer essentially contains the I/O components of the system, the GUI, REST APIs, mobile applications or console shells, and anything directly related to them. It is the starting point of our application.
For this starting point solution, it contains the following:
- ASP.NET Core MVC web application using Razor Components
- A shared class library containing common Razor Components, such as toast notifications, modal components, Blazor Select2, DataTablesJS integration, and CRUD buttons.
4. The Common Layer
This single-class library contains common types used across all other layers. What you would typically include in this library are things that you would wrap up into a NuGet package and use in multiple solutions. For clarification, this does not represent the Shared Kernel strategic pattern in DDD. Some of these include:
- A generic Result wrapper
- Paged result models for query operations
- CLR type extensions
- Notification models
- Custom attributes and converters
Common Architectures in Asp.Net Core
In the case of traditional .NET Applications, it is always deployed as a Single Unit related to an executable or a single web-based application running in the IIS app domain. It is the simple approach of the deployment model. This Model is used in the case of many internal and external small public applications. But despite single-unit deployment, some business applications always benefit from the logical separation into several layers.
A Monolithic application is the best example of a Single-unit application, which is entirely self-contained in behavior or functionality. Of course, these types of applications may interact with other services or data access layers. Still, it always runs within its process when performing its operation, and the entire application is deployed as a single unit. For this type of application, if we require to scale the application horizontally, we need the whole application to be duplicated across multiple servers or VMs.
In the case of application architecture, the smallest possible number of projects is one. In this architecture, the application's business logic is a single project, compiled into a single assembly, and deployed as a single unit. A new ASP.Net Core Project, either we create using Visual Studio or by the command line, always starts as a Single "all-in-one" monolith. It always contains all of the application's behavior, including presentation and data access logic. The image shows the file structure of a single project app.
In the case of this type of Single Project Scenario, we can achieve the separation of concerns with the help of using folders. The default template includes different folders for MVC Pattern responsibilities like Models, Views, and Controllers. Also, we can add additional folders like Data and Service as per our requirements. But this simple, single-project-based monolithic solution always has some disadvantages. For example, as the size of the projects increases along with the complexity, the number of files and folders will increase. In this way, file management becomes very tough to maintain.
As the application complexity increases, one of the best ways to manage it is to break down the application's responsibility or functionality. This approach follows the separation of concern principle and helps us organize a large codebase. With the help of layered architecture, we can achieve many advantages except code organization. Using the code into different layers can reuse the standard low-level functionality throughout the application. Furthermore, this approach allows us to standardize the application on a single implementation followed by the Don't Repeat Yourself (DRY) principle.
In a layered architecture, applications are broken down into multiple layers, and each layer can communicate with other layers. This architecture helps us to achieve encapsulation. Because when we need to change a particular layer, it will affect only those layers that work with it. So, by reducing the layer's dependency on each other, we can minimize the impacts of changes which can be mitigated so that a single change does not impact the entire application.
The most common applications always follow the Traditional N-Layer Architecture.
As mentioned earlier, this architecture always contains layers, generally abbreviated as UI, BL (Business Logic Layer), and DAL (Data Access Layer). Users always request the UI in this architecture, and UI layers communicate with the BL layers. The BL layer then communicates with the data access layers. However, the UI Layer can't directly communicate with the DAL layers. The below images show the example solution structure where the application breaks down into three projects as per the responsibility or layers.
Clean Architecture is a better way to organize moderate to high-complexity applications. It helps us separate dependencies and keep them isolated from business logic and the application's domain model. ASP.NET Core works entirely with the Clean Architecture approach, provided that the initial solution structure is set up correctly. Using a solution template in ASP.NET Core can help ensure you get your application started on the right track. If you want more knowledge you can get help from ASP.NET Core Training from Dot Net Tricks.