Clean Architecture in .NET (Full Deep Dive)
Structure your .NET applications into layers that are testable, maintainable, and independent of frameworks and databases.
What You'll Learn
- • The four layers: Domain, Application, Infrastructure, Presentation
- • Domain entities with invariants and factory methods
- • Application use cases with commands and queries
- • Infrastructure implementations and DI wiring
🏰 Real-World Analogy
Clean Architecture is like a medieval castle. The Domain (king) sits at the centre — it knows nothing about the outside world. The Application layer (advisors) coordinates activities. Infrastructure (walls, gates) connects to the outside. Presentation (gatehouse) faces visitors. Dependencies always point inward — the king never depends on the walls.
Domain Layer — Pure Business Logic
The innermost layer contains entities, value objects, and domain rules. It has zero dependencies on frameworks, databases, or UI. Business rules live here.
Domain Layer — Entities & Rules
Create domain entities with factory methods, invariants, and repository interfaces.
// ══════════════════════════════════════════════
// Domain Layer — pure business logic, NO dependencies
// ══════════════════════════════════════════════
namespace MyApp.Domain.Entities;
// Entity — has identity and lifecycle
public class Order
{
public Guid Id { get; private set; }
public string CustomerId { get; private set; }
public DateTime CreatedAt { get; private set; }
public OrderStatus Status { get; private set; }
private readonly List<OrderItem> _items = new();
...Application Layer — Use Cases
The Application layer orchestrates domain objects to fulfil use cases. It contains commands, queries, and handlers — but no direct database or HTTP logic.
Application Layer — Commands & Handlers
Orchestrate domain entities with use case handlers for commands and queries.
// ══════════════════════════════════════════════
// Application Layer — use cases / orchestration
// ══════════════════════════════════════════════
namespace MyApp.Application.UseCases;
// Command — represents an intent
public record CreateOrderCommand(string CustomerId, List<OrderItemDto> Items);
public record OrderItemDto(string ProductName, decimal Price, int Quantity);
// Use case handler — orchestrates domain objects
public class CreateOrderHandler
{
private readonly IOrderRepositor
...Infrastructure Layer — External Concerns
Infrastructure implements the interfaces defined in Domain. This is where EF Core, email services, and external APIs live. The DI container wires everything together.
Infrastructure — Repositories & DI Wiring
Implement repository interfaces with EF Core and register services in DI.
// ══════════════════════════════════════════════
// Infrastructure Layer — external concerns
// ══════════════════════════════════════════════
namespace MyApp.Infrastructure.Persistence;
// EF Core implementation of the domain repository
public class OrderRepository : IOrderRepository
{
private readonly AppDbContext _db;
public OrderRepository(AppDbContext db) => _db = db;
public async Task<Order?> GetByIdAsync(Guid id)
{
return await _db.Orders
.Include(
...Pro Tip
Create separate .csproj projects for each layer: MyApp.Domain, MyApp.Application, MyApp.Infrastructure, MyApp.Api. This enforces dependency rules at compile time — Domain can't accidentally reference Infrastructure.
Common Mistakes
- • Leaking EF Core entities into the Domain — use separate domain models
- • Putting business logic in controllers — controllers should only call use cases
- • Over-engineering simple CRUD apps — Clean Architecture adds value in complex domains
Lesson Complete!
You've mastered Clean Architecture in .NET. Next, dive into Domain-Driven Design to model complex business domains.
Sign up for free to track which lessons you've completed and get learning reminders.