00:29:17
Learn how to structure your .NET applications for maintainability, testability, and domain-centric design using Clean Architecture principles.
Clean Architecture, also known as Onion Architecture or Hexagonal Architecture (Ports and Adapters), represents a domain-centric approach to application design. Unlike traditional database-centered architectures where everything eventually depends on the database, Clean Architecture ensures that business logic remains independent of infrastructure concerns.
The core principle involves organizing dependencies so that they point inward toward the domain model, rather than having outer layers like UI depending on inner layers like data access. This is achieved through the Dependency Inversion Principle, using abstractions and interfaces defined in the core domain project.
This architectural approach is particularly valuable for teams practicing Domain-Driven Design (DDD) who want to maintain focus on their domain model rather than infrastructure concerns. It's ideal for applications with complex business logic that requires extensive automated testing.
The architecture acts as a enforcement mechanism, using the compiler to prevent accidental dependencies on infrastructure from creeping into the domain model. This provides guardrails that help teams maintain architectural consistency without relying solely on developer discipline.
The heart of Clean Architecture is the core project, which contains:
For applications using Command Query Responsibility Segregation (CQRS), a separate use cases project sits between the UI and domain model. This contains:
The infrastructure layer handles implementation details:
The web layer contains ASP.NET Core-specific components:
A sample task tracking system demonstrates these principles with two main aggregates: Contributors and Projects. The domain model contains business logic for operations like marking todo items as complete, while domain events handle side effects like sending notifications.
Specifications help avoid LINQ code duplication across the application by centralizing query logic in named, reusable components. Domain event handlers use dependency injection to perform infrastructure-dependent tasks without polluting the domain model.
The example uses FastEndpoints with Minimal APIs for thin endpoints that primarily delegate to mediators. This keeps web concerns separate from business logic while maintaining performance benefits.
A template is available to quickly start new projects with Clean Architecture:
dotnet new install Clean.Architecture.Solution.Template::8.0.0-preview2
dotnet new clean-arch -o YourCompany.YourProject
This template creates the solution structure with proper project dependencies and includes test projects, saving significant setup time.
Compared to traditional N-Tier architecture where dependencies flow from UI to Business to Data layers (all ultimately depending on the database), Clean Architecture inverts these dependencies. The core domain has no dependencies on external concerns, while infrastructure and UI depend inward on the domain abstractions.
This inversion enables easier testing (domain logic can be tested without infrastructure) and more flexible replacement of implementation details (changing databases or UI frameworks without affecting business logic).