The Core Idea
Dependencies point inward. The domain layer knows nothing about EF Core, ASP.NET, or SQL Server. Outer layers depend on inner layers — never the reverse.
Project Structure
MyApp.Domain ↠Entities, value objects, domain events
MyApp.Application ↠Use cases, interfaces, DTOs
MyApp.Infrastructure↠EF Core, external APIs, file storage
MyApp.Web ↠ASP.NET Core, controllers, Razor Pages
Repository Pattern
// In Application layer — no EF Core reference
public interface IPostRepository
{
Task<BlogPost?> GetBySlugAsync(string slug);
Task<IReadOnlyList<BlogPost>> GetPublishedAsync(int page, int size);
}
// In Infrastructure layer — EF Core implementation
public class PostRepository(BlogDbContext db) : IPostRepository
{
public Task<BlogPost?> GetBySlugAsync(string slug) =>
db.BlogPosts.AsNoTracking().FirstOrDefaultAsync(p => p.Slug == slug);
}
âš ï¸
Don't over-engineer. Clean Architecture adds layers. For a simple CRUD app with one developer, a well-structured single project is often better.
Conclusion
Clean Architecture pays dividends on large teams and long-lived systems. Apply it where complexity justifies the overhead.