MA
← All posts

November 2, 2025

Clean Architecture in ASP.NET Core: What Actually Matters

ASP.NET CoreArchitectureBest Practices

The folder structure isn't the point

Most articles on clean architecture in .NET spend their word count on folder names — Domain, Application, Infrastructure. That's the easy 20%. The part that actually determines whether a codebase is maintainable three years in is much less photogenic: dependency direction, and how disciplined the team stays about it under deadline pressure.

What breaks first

In every legacy ASP.NET codebase I've inherited, the first thing to erode is the boundary between the domain layer and everything else. A controller reaches directly into DbContext. A domain entity picks up a reference to a DTO. Each individual shortcut looks harmless. Two years later, changing a single business rule requires touching twelve files across three layers.

The fix isn't a stricter folder structure — it's making the dependency rule a code review checklist item, not a diagram nobody re-reads after week one.

Three rules that actually hold up

  1. Domain entities know nothing about persistence. No DbSet references, no EF Core attributes bleeding business logic into infrastructure concerns.
  2. Application services orchestrate, they don't implement. If a use case needs five lines of actual business logic, that logic lives on the entity or a domain service — not scattered across a handler.
  3. Infrastructure is the only layer allowed to change without a design conversation. Swapping SQL Server for PostgreSQL, or REST for gRPC, should never require touching domain code. If it does, the boundary already failed.

Where I actually draw the API boundary

Controllers in my projects do three things and nothing else: validate the request shape, call one application service method, and map the result. Any project where a controller method exceeds twenty lines is a project where business logic has quietly leaked into the transport layer.

This isn't dogma for its own sake — it's what makes a system testable without spinning up a database, and what lets a new engineer make a confident change on day three instead of week three.