Arhitectură DDD în .NET Core: Cum structuri proiectele backend în mod curat și scalabil
🔰 1. Ce este Domain-Driven Design (DDD)?
- Inventat de Eric Evans, axat pe modele centrate pe domeniu.
- Separă codul în limbajul experților (Ubiquitous Language).
- Avantajele majore:
- Cod ușor de testat
- Separare clară a responsabilităților
- Scalabilitate logică pe termen lung
📐 2. Structurarea soluției .NET Core în layere (proiecte)
Organizarea recomandată a soluției:
/src
├── Blog.Domain <- modele, entități, Value Objects
├── Blog.Application <- servicii de aplicație, comenzi, DTO-uri
├── Blog.Infrastructure <- EF Core, repositories, external deps
└── Blog.API <- Web API Controllers, DI, prezentare
Explicarea fiecărui layer:
• Domain: logică pură, fără dependențe externe
• Application: orchestrare între servicii, fără acces direct la DB
• Infrastructure: detalii tehnice (SQL, Redis, Email)
• API: controlere, autentificare, DTO-uri externe
🧱 3. Modelul de domeniu – Crearea agregatului Post
public class Post : Entity<Guid>
{
public Title Title { get; private set; }
public Slug Slug { get; private set; }
public PostContent Content { get; private set; }
public DateTime PublishedAt { get; private set; }
public Post(Title title, Slug slug, PostContent content)
{
Title = title;
Slug = slug;
Content = content;
PublishedAt = DateTime.UtcNow;
}
}
Value Object: Slug
public class Slug : ValueObject
{
public string Value { get; }
private Slug(string value)
{
Value = value;
}
public static Slug FromTitle(string title)
{
var slug = Regex.Replace(title.ToLower(), @"[^a-z0-9]+", "-");
return new Slug(slug.Trim('-'));
}
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Value;
}
}
📦 4. Repository Pattern + Unit of Work
Interfață generică:
public interface IRepository<T> where T : class
{
Task<T?> GetByIdAsync(Guid id);
Task AddAsync(T entity);
void Remove(T entity);
}
Unit of Work:
public interface IUnitOfWork
{
Task<int> SaveChangesAsync();
}
În Infrastructure, vom implementa PostRepository cu EF Core.
💡 5. Application Layer + MediatR
Comandă de creare post:
public record CreatePostCommand(string Title, string Content) : Irequest<Guid>;
Handler:
public class CreatePostHandler : IRequestHandler<CreatePostCommand, Guid>
{
private readonly IPostRepository _postRepo;
private readonly IUnitOfWork _uow;
public CreatePostHandler(IPostRepository postRepo, IUnitOfWork uow)
{
_postRepo = postRepo;
_uow = uow;
}
public async Task<Guid> Handle(CreatePostCommand request, CancellationToken ct)
{
var slug = Slug.FromTitle(request.Title);
var post = new Post(new Title(request.Title), slug, new PostContent(request.Content));
await _postRepo.AddAsync(post);
await _uow.SaveChangesAsync();
return post.Id;
}
}
🔚 Concluzie
Acest articol marchează începutul implementării backend-ului nostru folosind DDD în .NET Core. Am discutat conceptele cheie, structura proiectului și am implementat un prim agregat (Post) cu pattern-uri robuste.
🧭 Ce urmează
În articolul următor, vom:
• Adăuga un controller REST pentru POST /posts
• Conecta frontend-ul React la acest endpoint
• Afișa și trimite articole din UI