Section 4 of 5

Clean Architecture

🎯 What You'll Learn

  • What is Clean Architecture
  • Layers and dependencies
  • Domain layer
  • Application layer
  • Infrastructure layer

What is Clean Architecture?

Clean Architecture organizes code into layers with dependencies pointing inward, keeping business logic independent of frameworks and infrastructure.

Layers

Layer Responsibility Dependencies
Domain Business entities and rules None
Application Use cases and business logic Domain
Infrastructure Data access, external services Application, Domain
Presentation UI, API controllers Application

Project Structure

Solution Structure Text
InvenTrack/
├── InvenTrack.Domain/
│   ├── Entities/
│   │   ├── Product.cs
│   │   ├── Order.cs
│   ├── Interfaces/
│   │   ├── IProductRepository.cs
├── InvenTrack.Application/
│   ├── Services/
│   │   ├── ProductService.cs
│   ├── DTOs/
│   │   ├── ProductDto.cs
├── InvenTrack.Infrastructure/
│   ├── Data/
│   │   ├── InvenTrackDbContext.cs
│   ├── Repositories/
│   │   ├── ProductRepository.cs
├── InvenTrack.Web/
│   ├── Controllers/
│   │   ├── ProductsController.cs

Domain Layer

Domain/Entities/Product.cs C#
namespace InvenTrack.Domain.Entities;

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int Quantity { get; set; }

    public bool IsLowStock() => Quantity < 10;
}
Domain/Interfaces/IProductRepository.cs C#
namespace InvenTrack.Domain.Interfaces;

public interface IProductRepository
{
    Task<Product> GetByIdAsync(int id);
    Task<IEnumerable<Product>> GetAllAsync();
    Task AddAsync(Product product);
}

Application Layer

Application/DTOs/ProductDto.cs C#
namespace InvenTrack.Application.DTOs;

public class ProductDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}
Application/Services/ProductService.cs C#
namespace InvenTrack.Application.Services;

public class ProductService
{
    private readonly IProductRepository _repository;

    public ProductService(IProductRepository repository)
    {
        _repository = repository;
    }

    public async Task<IEnumerable<ProductDto>> GetAllProductsAsync()
    {
        var products = await _repository.GetAllAsync();
        
        return products.Select(p => new ProductDto
        {
            Id = p.Id,
            Name = p.Name,
            Price = p.Price
        });
    }
}

Infrastructure Layer

Infrastructure/Repositories/ProductRepository.cs C#
namespace InvenTrack.Infrastructure.Repositories;

public class ProductRepository : IProductRepository
{
    private readonly InvenTrackDbContext _context;

    public ProductRepository(InvenTrackDbContext context)
    {
        _context = context;
    }

    public async Task<Product> GetByIdAsync(int id)
    {
        return await _context.Products.FindAsync(id);
    }
}

Presentation Layer

Web/Controllers/ProductsController.cs C#
namespace InvenTrack.Web.Controllers;

public class ProductsController : Controller
{
    private readonly ProductService _productService;

    public ProductsController(ProductService productService)
    {
        _productService = productService;
    }

    [HttpGet]
    public async Task<IActionResult> Index()
    {
        var products = await _productService.GetAllProductsAsync();
        return View(products);
    }
}

Key Takeaways

  • Clean Architecture: Layers with inward dependencies
  • Domain: Business entities and interfaces (no dependencies)
  • Application: Use cases and DTOs (depends on Domain)
  • Infrastructure: Data access (depends on Domain)
  • Presentation: UI/API (depends on Application)
  • Benefits: Testable, maintainable, framework-independent