Есть ли Application слой в проекте eShopOnContainers?

«Есть ли Application слой в проекте eShopOnContainers?» — вопрос из категории Архитектура, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, в референсной архитектуре eShopOnContainers явно выделен Application слой. Он находится между Presentation (веб-API) и Domain слоями и реализует Use Cases (сценарии использования) приложения.

Роль и обязанности Application слоя в eShop:

  • Оркестрация потока выполнения: Координация работы Domain-объектов (сущностей, агрегатов) и Infrastructure-сервисов для выполнения конкретной бизнес-операции.
  • Работа с DTO (Data Transfer Objects): Преобразование Domain-моделей в объекты, удобные для передачи через API, и наоборот. Важно: В этом слое нет бизнес-правил.
  • Валидация команд: Проверка входных данных на корректность формата (например, с помощью FluentValidation) перед передачей в Domain.
  • Управление транзакциями: Обеспечение целостности одной бизнес-операции, часто через Unit of Work.
  • Публикация Domain Events: После успешного выполнения операции слой Application может публиковать события для уведомления других частей системы.

Пример из eShopOnContainers (Application Service):

// Ordering.API.Application.Commands.CreateOrderCommandHandler
public class CreateOrderCommandHandler
    : IRequestHandler<CreateOrderCommand, bool>
{
    private readonly IOrderRepository _orderRepository;
    private readonly IIdentityService _identityService;
    private readonly IMediator _mediator;

    public async Task<bool> Handle(CreateOrderCommand command, CancellationToken cancellationToken)
    {
        // 1. Создание Domain-объекта (Агрегата Order) на основе команды
        var address = new Address(...);
        var order = new Order(command.UserId, command.UserName, address, command.CardTypeId, ...);

        foreach (var item in command.OrderItems)
        {
            order.AddOrderItem(item.ProductId, item.ProductName, ..., item.Units);
        }

        // 2. Сохранение агрегата через Repository (инфраструктура)
        _orderRepository.Add(order);

        // 3. Сохранение изменений (Unit of Work)
        var result = await _orderRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        // 4. Публикация Domain Event через Mediator
        // (например, OrderStartedDomainEvent для запуска Saga оплаты)
        await _mediator.Publish(new OrderStartedDomainEvent(order), cancellationToken);

        return result;
    }
}

Этот обработчик команды — типичный компонент Application слоя: он получает команду CreateOrderCommand (DTO), использует Domain-логику для создания заказа, сохраняет его и публикует событие.