.NET 10 is here — faster, smarter, and more powerful. What are you waiting for? Upgrade your skills today with us!
← Back to Blogs
.NETNov 21, 2025
Clean Architecture in ASP.NET Core

Clean Architecture in ASP.NET Core

👤 Rohan Kumawat⏱️ 16 min read

What is Clean Architecture in ASP.NET Core?

Clean Architecture is a software design pattern focused on making your application independent of frameworks, UI, database, and external services. It improves maintainability, testability, and scalability by separating your project into well-defined layers. The Dependency Rule states that dependencies must always point inward toward the core business logic.

Core Principles

Clean Architecture ensures independence from frameworks, UI, and database implementations. It allows your business logic to stay pure and reusable across multiple applications like Web, Mobile, or Desktop. All dependencies must flow inward, making the core system stable and long-lasting.

Clean Architecture Layer Structure

A typical Clean Architecture setup in ASP.NET Core contains four layers: Domain, Application, Infrastructure, and WebAPI. Domain holds entities and core logic, Application stores business rules and use cases (often using CQRS), Infrastructure handles EF Core database access and external services, and WebAPI exposes the application through controllers and routes.

Folder Structure

Below is the recommended folder structure:

/src /Domain /Application /Infrastructure /WebAPI

Step 1: Create a New Solution

Create the main solution using .NET CLI.

dotnet new sln -n CleanArchitectureDemo

Step 2: Create Four Projects

Create the Domain, Application, Infrastructure, and WebAPI projects.

dotnet new classlib -n Domain dotnet new classlib -n Application dotnet new classlib -n Infrastructure dotnet new webapi -n WebAPI

Step 3: Add Projects to Solution

After creating the folders, add them to your solution.

dotnet sln add Domain/Domain.csproj dotnet sln add Application/Application.csproj dotnet sln add Infrastructure/Infrastructure.csproj dotnet sln add WebAPI/WebAPI.csproj

Step 4: Add Project References

Define how layers depend on each other according to Clean Architecture rules.

dotnet add Application/Application.csproj reference Domain/Domain.csproj dotnet add Infrastructure/Infrastructure.csproj reference Application/Application.csproj dotnet add WebAPI/WebAPI.csproj reference Application/Application.csproj dotnet add WebAPI/WebAPI.csproj reference Infrastructure/Infrastructure.csproj

Domain Layer Example

A simple entity inside the Domain layer.

namespace Domain.Entities { public class Product { public int Id { get; set; } public string Name { get; set; } = string.Empty; public decimal Price { get; set; } } }

Application Layer Example (CQRS Use Case)

This layer defines the application logic, interfaces, and use cases.

using Domain.Entities; namespace Application.Products.Queries { public class GetProductsQuery { } public interface IGetProductsQueryHandler { Task> HandleAsync(); } }

Infrastructure Layer Example (EF Core Implementation)

Infrastructure contains real database logic and external service implementations.

using Domain.Entities; using Microsoft.EntityFrameworkCore; namespace Infrastructure.Data { public class AppDbContext : DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } public DbSet<Product> Products => Set<Product>(); } }
using Application.Products.Queries; using Infrastructure.Data; using Microsoft.EntityFrameworkCore; namespace Infrastructure.Handlers { public class GetProductsQueryHandler : IGetProductsQueryHandler { private readonly AppDbContext _context; public GetProductsQueryHandler(AppDbContext context) { _context = context; } public async Task<List<Domain.Entities.Product>> HandleAsync() { return await _context.Products.ToListAsync(); } } }

WebAPI Layer Example (Controller)

The presentation layer exposes API endpoints for the application.

using Application.Products.Queries; using Microsoft.AspNetCore.Mvc; namespace WebAPI.Controllers { [ApiController] [Route("api/[controller]")] public class ProductsController : ControllerBase { private readonly IGetProductsQueryHandler _handler; public ProductsController(IGetProductsQueryHandler handler) { _handler = handler; } [HttpGet] public async Task GetProducts() { var products = await _handler.HandleAsync(); return Ok(products); } } }

Register Services in Program.cs

Configure dependency injection for Application and Infrastructure layers.

using Application.Products.Queries; using Infrastructure.Data; using Infrastructure.Handlers; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); builder.Services.AddScoped<IGetProductsQueryHandler, GetProductsQueryHandler>(); builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); app.Run();

Run the Application

Finally, run the API using:

dotnet run --project WebAPI/WebAPI.csproj