- Published on
Как применять Clean Architecture в ASP.NET CORE - Domain
- Authors
- Name
- Николай Маракасов
В прошлой статье я рассмотрел прикладной слой Clean Architecture, теперь пришло время изучить центральный слой — доменный.
Domain
На диаграмме, которую мы разбирали в первой статье, этот слой назывался Entities, но я предпочитаю называть его Domain, так как это ближе к предметно-ориентированному проектированию (DDD).
В зависимости от сложности бизнес-логики этот уровень может проектироваться по-разному, но его главное предназначение — реализация корпоративных бизнес-правил.

Как и в слое Application, я организую код на основе бизнес-контекста, а не технических аспектов. Вместо структуры:
- Entities
- Orders
- Interfaces
- OrdersRepository
- Exceptions
- Services
мы группируем код так, как показано на изображении выше, складывая всю логику, связанную с заказами, в директорию Orders. Исключение составляют технические детали, такие как интерфейсы IEntity
или IDomainEvent
.
Реализация сущности Order
Рассмотрим сущность Order, которая описывает заказ. Она содержит не только данные, но и поведение — в нашем случае логику переключения статусов заказа.
public sealed class Order : IEntity<Guid>
{
public Order(Guid id, List<OrderLine> orderLines)
{
if (id == Guid.Empty)
throw new ArgumentException("Order ID cannot be empty");
if (orderLines == null || orderLines.Count == 0)
throw new ArgumentException("Order lines cannot be empty");
Id = id;
Status = OrderStatus.Created;
OrderLines = orderLines;
}
public Guid Id { get; }
public ICollection<OrderLine> OrderLines { get; init; }
public OrderStatus Status { get; private set; }
public void Complete()
{
if (Status == OrderStatus.Completed)
throw new OrderChangeStatusException("Order is already completed");
Status = OrderStatus.Completed;
}
}
Почему важно инкапсулировать логику в сущности?
- Изоляция бизнес-правил — логика переключения статусов теперь не разбросана по всему коду, а находится в одном месте.
- Облегчение работы прикладного слоя — Application выполняет лишь координацию процессов, не вдаваясь в детали реализации бизнес-логики.
Репозиторий IOrderRepository
Интерфейс репозитория отвечает за работу с доменной сущностью Order и, как правило, содержит базовые методы. Он располагается в том же модуле, где и сама сущность.
public interface IOrderRepository
{
Task<Order> GetById(Guid orderId, CancellationToken cancellationToken);
Task<int> Update(Order order, CancellationToken cancellationToken);
Task<int> Add(Order order, CancellationToken cancellationToken);
Task<int> Delete(Order order, CancellationToken cancellationToken);
}
Реализация этого интерфейса находится в слое Infrastructure.
Когда выносить логику в домен?
Бизнес-логику можно начинать реализовывать на уровне Application и по мере её усложнения постепенно переносить в доменный слой. Помимо методов сущностей, бизнес-правила могут быть вынесены в доменные сервисы — их стоит использовать, когда:
- Логику нельзя привязать к конкретной сущности.
- Бизнес-процесс требует дополнительных зависимостей.
Заключение
Как я уже отмечал, сложность доменного слоя зависит от масштабов приложения и выбранного подхода к проектированию. Однако главное — этот слой должен быть изолирован от технических деталей и других частей системы, так как он является ядром приложения.