EngineeringSenior DeveloperArchitecture and Patterns

01 - Clean Architecture Blueprint

Kiến trúc phổ biến nhất cho enterprise .NET projects. Tách biệt business logic khỏi infrastructure, dễ test, dễ thay đổi technology.


Tổng Quan

Dependency Rule: Mũi tên CHỈ hướng vào trong. Domain KHÔNG biết về Infrastructure.


Khi Nào Dùng / Không Dùng

✅ Dùng khi❌ Không dùng khi
Business logic phức tạp, thay đổi thường xuyênSimple CRUD app (< 10 entities)
Team > 3 devs, cần rõ ràng ownershipPrototype / MVP cần ship nhanh
Cần testability cao (unit test domain)Script, ETL, background jobs đơn giản
Dự kiến thay đổi database/infrastructureSolo dev, side project

Dự án hay dùng: ERP, eCommerce, Banking, Insurance, Healthcare, Logistics.


Project Structure (.sln)

MyApp/
├── MyApp.sln
│
├── src/
│   ├── MyApp.Domain/                  ← Core (0 dependencies)
│   │   ├── Entities/
│   │   │   ├── Order.cs
│   │   │   └── OrderItem.cs
│   │   ├── ValueObjects/
│   │   │   ├── Money.cs
│   │   │   └── Email.cs
│   │   ├── Events/
│   │   │   └── OrderCreatedEvent.cs
│   │   ├── Enums/
│   │   │   └── OrderStatus.cs
│   │   ├── Exceptions/
│   │   │   └── DomainException.cs
│   │   └── Interfaces/
│   │       └── IOrderRepository.cs
│   │
│   ├── MyApp.Application/            ← Use Cases
│   │   ├── Common/
│   │   │   ├── Behaviors/
│   │   │   │   ├── ValidationBehavior.cs
│   │   │   │   └── LoggingBehavior.cs
│   │   │   ├── Interfaces/
│   │   │   │   ├── IUnitOfWork.cs
│   │   │   │   └── ICurrentUser.cs
│   │   │   └── Models/
│   │   │       └── Result.cs
│   │   ├── Orders/
│   │   │   ├── Commands/
│   │   │   │   ├── CreateOrder/
│   │   │   │   │   ├── CreateOrderCommand.cs
│   │   │   │   │   ├── CreateOrderHandler.cs
│   │   │   │   │   └── CreateOrderValidator.cs
│   │   │   ├── Queries/
│   │   │   │   └── GetOrderById/
│   │   │   │       ├── GetOrderByIdQuery.cs
│   │   │   │       └── GetOrderByIdHandler.cs
│   │   │   └── DTOs/
│   │   │       └── OrderDto.cs
│   │   └── DependencyInjection.cs
│   │
│   ├── MyApp.Infrastructure/         ← Implementations
│   │   ├── Persistence/
│   │   │   ├── AppDbContext.cs
│   │   │   ├── Configurations/
│   │   │   │   └── OrderConfiguration.cs
│   │   │   ├── Repositories/
│   │   │   │   └── OrderRepository.cs
│   │   │   ├── Interceptors/
│   │   │   │   └── AuditableEntityInterceptor.cs
│   │   │   └── Migrations/
│   │   ├── Services/
│   │   │   ├── EmailService.cs
│   │   │   └── CacheService.cs
│   │   └── DependencyInjection.cs
│   │
│   └── MyApp.API/                    ← Entry Point
│       ├── Controllers/
│       │   └── OrdersController.cs
│       ├── Middleware/
│       │   └── ExceptionHandlerMiddleware.cs
│       ├── Program.cs
│       └── appsettings.json
│
└── tests/
    ├── MyApp.Domain.Tests/
    ├── MyApp.Application.Tests/
    └── MyApp.API.IntegrationTests/

Project References (Dependency Direction)


NuGet Checklist

xml
<!-- MyApp.Domain (KHÔNG có NuGet ngoại trừ MediatR contracts) -->
<PackageReference Include="MediatR.Contracts" Version="2.*" />

<!-- MyApp.Application -->
<PackageReference Include="MediatR" Version="12.*" />
<PackageReference Include="FluentValidation" Version="11.*" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.*" />
<PackageReference Include="AutoMapper" Version="13.*" /> <!-- hoặc Mapster -->

<!-- MyApp.Infrastructure -->
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.*" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.*" />
<PackageReference Include="StackExchange.Redis" Version="2.*" />

<!-- MyApp.API -->
<PackageReference Include="Serilog.AspNetCore" Version="8.*" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.*" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.*" />

Code Setup Cốt Lõi

Program.cs (API Layer)

csharp
var builder = WebApplication.CreateBuilder(args);

// Layer registrations
builder.Services
    .AddApplication()       // MediatR, FluentValidation, Behaviors
    .AddInfrastructure(builder.Configuration); // EF Core, Redis, Services

builder.Services.AddControllers();
builder.Services.AddSwaggerGen();

var app = builder.Build();

app.UseExceptionHandler();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

Application DI Registration

csharp
public static class DependencyInjection
{
    public static IServiceCollection AddApplication(this IServiceCollection services)
    {
        var assembly = typeof(DependencyInjection).Assembly;

        services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(assembly));
        services.AddValidatorsFromAssembly(assembly);

        // Pipeline Behaviors (order matters!)
        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));

        return services;
    }
}

Infrastructure DI Registration

csharp
public static class DependencyInjection
{
    public static IServiceCollection AddInfrastructure(
        this IServiceCollection services, IConfiguration config)
    {
        services.AddDbContext<AppDbContext>(options =>
            options.UseSqlServer(config.GetConnectionString("Default")));

        services.AddScoped<IOrderRepository, OrderRepository>();
        services.AddScoped<IUnitOfWork>(sp => sp.GetRequiredService<AppDbContext>());

        return services;
    }
}