Clean Architecture ile .NET 8 API — Pratik Rehber
Clean Architecture ile .NET 8 API — Pratik Rehber
Clean Architecture Nedir?
Robert C. Martin (Uncle Bob) tarafından ortaya atılan Clean Architecture, yazılımı iç içe geçmiş katmanlara ayıran bir tasarım felsefesidir. Temel kural şudur: bağımlılıklar her zaman içe doğru akar — dış katmanlar iç katmanlara bağımlıdır, tersi asla olmaz.
Katman Yapısı
src/
├── Domain/ # Entity'ler, Value Object'ler, Domain Event'ler
├── Application/ # Use Case'ler, Interface'ler, DTO'lar
├── Infrastructure/ # EF Core, Harici Servisler, Repository'ler
└── WebAPI/ # Controller'lar, Middleware, DI Konfigürasyonu
1. Domain Katmanı
Uygulamanın kalbi. Başka hiçbir katmana veya NuGet paketine bağımlılığı yoktur.
public class Product
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public decimal Price { get; private set; }
public Product(string name, decimal price)
{
Id = Guid.NewGuid();
Name = name;
Price = price;
}
}
2. Application Katmanı
İş mantığını, use case'leri ve interface tanımlarını barındırır.
public interface IProductRepository
{
Task<Product?> GetByIdAsync(Guid id, CancellationToken ct);
Task AddAsync(Product product, CancellationToken ct);
}
public record GetProductQuery(Guid Id) : IRequest<ProductDto>;
public class GetProductHandler : IRequestHandler<GetProductQuery, ProductDto>
{
private readonly IProductRepository _repo;
public GetProductHandler(IProductRepository repo) => _repo = repo;
public async Task<ProductDto> Handle(GetProductQuery query, CancellationToken ct)
{
var product = await _repo.GetByIdAsync(query.Id, ct)
?? throw new NotFoundException(nameof(Product), query.Id);
return new ProductDto(product.Id, product.Name, product.Price);
}
}
3. Infrastructure Katmanı
Application katmanında tanımlanan interface'leri implement eder. EF Core, harici API'lar, dosya sistemi — hepsi burada yaşar.
public class ProductRepository : IProductRepository
{
private readonly AppDbContext _context;
public ProductRepository(AppDbContext context) => _context = context;
public async Task<Product?> GetByIdAsync(Guid id, CancellationToken ct)
=> await _context.Products.FindAsync(new object[] { id }, ct);
public async Task AddAsync(Product product, CancellationToken ct)
{
await _context.Products.AddAsync(product, ct);
await _context.SaveChangesAsync(ct);
}
}
4. WebAPI Katmanı
Yalnızca HTTP katmanıyla ilgilenir. Controller'lar incedir — iş mantığını Application katmanına devreder.
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IMediator _mediator;
public ProductsController(IMediator mediator) => _mediator = mediator;
[HttpGet("{id:guid}")]
public async Task<IActionResult> Get(Guid id, CancellationToken ct)
{
var result = await _mediator.Send(new GetProductQuery(id), ct);
return Ok(result);
}
}
Dependency Injection Kurulumu
// Program.cs
builder.Services.AddApplication();
builder.Services.AddInfrastructure(builder.Configuration);
// Application/DependencyInjection.cs
public static IServiceCollection AddApplication(this IServiceCollection services)
{
services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
return services;
}
Temel Çıkarımlar
- Domain dış dünyadan habersizdir
- Application sistemin ne yaptığını tanımlar, nasıl yaptığını değil
- Infrastructure nasıl yapıldığını bilir — veritabanı, API, dosya
- WebAPI sadece bir iletim mekanizmasıdır
Ne Zaman Kullanmalısınız?
✅ Birden fazla geliştiriciyle çalışılan orta-büyük projeler
✅ Uzun ömürlü, zamanla büyüyecek uygulamalar
✅ Test edilebilirlik ve sürdürülebilirlik gerektiren projeler
❌ Basit CRUD API'lar veya küçük dahili araçlar — bu durumlarda fazla karmaşık olur
Son Söz
Clean Architecture katı bir kural kitabı değil, bir zihniyettir. Amaç; iş mantığınızı bağımsız, test edilebilir ve altyapı kaygılarından izole tutmaktır. Sade başlayın, karmaşıklık arttıkça katmanları genişletin.
Mimari, uygulamanın hangi framework'ü kullandığını değil, ne yaptığını haykırmalıdır.