.NET 8 Clean Architecture Setup
Clean Architecture Overview
- Opinionated way of structuring code.
- Emphasizes separating the application into layers (Domain, Application, Infrastructure and Presentation) and ensuring dependencies flow inward.
- Each layer only knows about the inner layers.
- Architecture enforces design policies.
Clean Architecture vs Onion Architecture
Both emphasize layer separation and the direction of dependencies, but Clean Architecture makes a stronger distinction between use cases (Application layer) and technical concerns (Infrastructure).
Domain Driven Design (DDD) 101
- Focuses on creating a model of the business domain.
- Concepts such as Entities, Value Objects, Aggregates, Repositories and Services.
SOLID Principles 101
The SOLID principles are a set of design guidelines that promote maintainable, scalable, and flexible software systems. They provide a foundation that Clean Architecture builds upon. Lets take a quick look how each principle aligns with Clean Architecture:
- Single Responsibility Principle (SRP)
- Separation into layers ensures each part of the system has one responsibility.
- Open/Closed Principle (OCP)
- Clean Architecture’s dependency inversion allows extending functionality (new Infrastructure services, for instance) without modifying core logic.
- Liskov Substitution Principle (LSP)
- By enforcing interface-driven development, Clean Architecture allows interchangeable components (e.g., repositories, services) without impacting functionality.
- Interface Segregation Principle (ISP)
- Interfaces are designed to be minimal, providing only what’s necessary for the layer that consumes them.
- Dependency Inversion Principle (DIP)
- Clean Architecture ensures high-level policies (business logic) are independent of low-level details (Infrastructure). All dependencies are abstracted through interfaces.
Layers in Clean Architecture
-
Domain: Core business logic and rules, with no external dependencies. If defines Entities, Value Objects, Domain events, Domain services and Interfaces/Abstractions. It is independant of any framework of database.
-
Application: Orchestration of the business logic in the domain layer. It defines Use Cases, DTOs and Application Services (or optionally CQRS). It depends on the Domain layer but not on the Infrastructure or Presentation.
-
Infrastructure: Deals with external concerns like databases, APIs, file systems, etc. It implements interfaces defined in the Application and Domain layers. Sometimes, Infrastructure and Persistence are separated to ensure a better distinction of responsabilities.
-
Presentation: This layer interacts with the outside world, often through a Web API (e.g. REST API) or user interface. It defines the entry point to the system, API endpoints, Middleware and Dependency Injection setup.
Quick Overview of CQRS
- It is a Design Pattern: Command and Query Responsibility Segregation
- Separates a service’s write tasks (commands) from its read tasks (queries).
- Not needed, you can just implement Use Case in Service classes, but…
- Benefits of CQRS
- Single responsibility principle
- Interface Segregation principle
- Decorator pattern
- Loose coupling
- Cons
- Indirection
File System Hierarchy Example
Take a SurgicalManagement project as an example:
SurgicalManagement.Domain
-> DomainEntities
-> DomainEvents
-> ValueObjects
-> DomainServicesInterfaces
-> Aggregates
-> DomainValidations
SurgicalManagement.Application
-> UseCases
-> Commands (for CQRS)
-> Queries (for CQRS)
-> Abstractions/Contracts/Interfaces
-> CommonInterfaces
-> Specifications
-> ApplicationServices
-> Exceptions
-> DTOs
-> Behaviours
-> ApplicationValidations
SurgicalManagement.Infrastructure
-> IdentityServices
-> QueueStorage
-> PaymentServices
-> Notifications
-> ThirdPartyServices
-> Caching
-> EventStore
-> Monitoring
SurgicalManagement.Persistence
-> DataContext
-> Repositories
-> DataSeeding
-> DataMigrations
SurgicalManagement.CrossCutting
-> Logging
-> ExceptionHandling
-> Validation
-> Security
-> Configuration
SurgicalManagement.Presentation
-> Controllers
-> Views
-> Middlewares
-> DependencyInjection
SurgicalManagement.Tests
-> TestFramework (e.g. xUnit, NUnit, etc)
-> DomainTests
-> ApplicationTests
-> InfrastructureTests
-> PresentationTests
Creating Project Using .NET CLI
# Solution
dotnet new sln -n SurgicalManagement
# Domain Project
dotnet new classlib -n SurgicalManagement.Domain
dotnet sln add SurgicalManagement.Domain/SurgicalManagement.Domain.csproj
# Application Project
dotnet new classlib -n SurgicalManagement.Application
dotnet sln add SurgicalManagement.Application/SurgicalManagement.Application.csproj
# Infrastructure Project
dotnet new classlib -n SurgicalManagement.Infrastructure
dotnet sln add SurgicalManagement.Infrastructure/SurgicalManagement.Infrastructure.csproj
# Persistence Project
dotnet new classlib -n SurgicalManagement.Persistence
dotnet sln add SurgicalManagement.Persistence/SurgicalManagement.Persistence.csproj
# CrossCutting Project
dotnet new classlib -n SurgicalManagement.CrossCutting
dotnet sln add SurgicalManagement.CrossCutting/SurgicalManagement.CrossCutting.csproj
# Presentation Project
dotnet new webapi -n SurgicalManagement.Presentation
dotnet sln add SurgicalManagement.Presentation/SurgicalManagement.Presentation.csproj
# Tests Project
dotnet new xunit -n SurgicalManagement.Tests
dotnet sln add SurgicalManagement.Tests/SurgicalManagement.Tests.csproj
# Add Project References
dotnet add SurgicalManagement.Application/SurgicalManagement.Application.csproj reference SurgicalManagement.Domain/SurgicalManagement.Domain.csproj
dotnet add SurgicalManagement.CrossCutting/SurgicalManagement.CrossCutting.csproj reference SurgicalManagement.Application/SurgicalManagement.Application.csproj
dotnet add SurgicalManagement.Infrastructure/SurgicalManagement.Infrastructure.csproj reference SurgicalManagement.CrossCutting/SurgicalManagement.CrossCutting.csproj
dotnet add SurgicalManagement.Persistence/SurgicalManagement.Persistence.csproj reference SurgicalManagement.CrossCutting/SurgicalManagement.CrossCutting.csproj
dotnet add SurgicalManagement.Presentation/SurgicalManagement.Presentation.csproj reference SurgicalManagement.CrossCutting/SurgicalManagement.CrossCutting.csproj
dotnet add SurgicalManagement.Tests/SurgicalManagement.Tests.csproj reference SurgicalManagement.CrossCutting/SurgicalManagement.CrossCutting.csproj
dotnet add SurgicalManagement.Tests/SurgicalManagement.Tests.csproj reference SurgicalManagement.Infrastructure/SurgicalManagement.Infrastructure.csproj
dotnet add SurgicalManagement.Tests/SurgicalManagement.Tests.csproj reference SurgicalManagement.Persistence/SurgicalManagement.Persistence.csproj
dotnet add SurgicalManagement.Tests/SurgicalManagement.Tests.csproj reference SurgicalManagement.Presentation/SurgicalManagement.Presentation.csproj