← Назад к вопросам

Почему CatalogRepository вынесен в Infrastructure, а не в Application слой?

1.6 Junior🔥 71 комментариев
#Основы C# и .NET

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Архитектура слоев и расположение CatalogRepository

Вопрос о расположении CatalogRepository в слое Infrastructure вместо Application является фундаментальным для понимания принципов чистой архитектуры (Clean Architecture) и паттерна Onion Architecture или Vertical Slice Architecture, которые часто применяются в современных C# backend-приложениях. Это разделение основано на четкой стратегии разделения ответственности и управления зависимостями.

Основные принципы разделения слоев

В типичной многослойной архитектуре (например, основанной на принципах Clean Architecture от Robert C. Martin) выделяются следующие основные слои:

  • Domain (Core): Содержит бизнес-сущности (Entities), правила бизнес-логики (Business Rules), агрегаты (Aggregates) и интерфейсы репозиториев (Repository Interfaces). Это самый внутренний, независимый слой.
  • Application: Содержит бизнес-процессы и операции. Здесь находятся сервисы приложения (Application Services), DTO, CQRS-команды и запросы, интерфейсы для внешних сервисов, а также определяются интерфейсы репозиториев. Этот слой зависит только от Domain.
  • Infrastructure: Предоставляет конкретные реализации инфраструктурных компонентов: реализации репозиториев (например, CatalogRepository), доступ к данным (ORM, как EF Core), внешние API-клиенты, отправка email, файловые сервисы. Этот слой зависит от Application и Domain.

Почему CatalogRepository находится в Infrastructure

CatalogRepository — это конкретная реализация интерфейса репозитория (например, ICatalogRepository), который абстрагирует доступ к данным для каталога товаров. Его размещение в Infrastructure обусловлено следующими ключевыми причинами:

1. Инверсия зависимости (Dependency Inversion Principle)

Это один из ключевых принципов SOLID. Интерфейс ICatalogRepository объявляется в слое Application (или Domain), что позволяет логике приложения зависеть от абстракции, а не от конкретной реализации.

// Application Layer - Интерфейс (Абстракция)
public interface ICatalogRepository
{
    Task<Product> GetByIdAsync(int id);
    Task<List<Product>> GetAllAsync();
    Task AddAsync(Product product);
}

// Infrastructure Layer - Конкретная реализация
public class CatalogRepository : ICatalogRepository
{
    private readonly ApplicationDbContext _context;

    public CatalogRepository(ApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<Product> GetByIdAsync(int id)
    {
        return await _context.Products.FindAsync(id);
    }
    // ... другие методы
}

Приложение (Application и Domain слои) ссылается только на ICatalogRepository. Конкретная реализация CatalogRepository, которая зависит от EF Core и ApplicationDbContext, предоставляется извне через Dependency Injection в Infrastructure. Это делает центральную логику независимой от деталей инфраструктуры.

2. Разделение бизнес-логики и инфраструктурных деталей

  • Слой Application содержит чистую бизнес-логику: валидацию, orchestration процессов, применение бизнес-правил. Он не должен знать, как данные сохраняются — в SQL Server, PostgreSQL, Cosmos DB или даже в файле.
  • Слой Infrastructure отвечает за эти технические детали: подключение к БД, выполнение SQL-запросов, управление транзакциями, использование специфических функций ORM. CatalogRepository воплощает эти детали.

Такое разделение позволяет:

  • Легко тестировать слой Application с использованием mock-объектов или stub-ов для ICatalogRepository.
  • Заменять источник данных без изменения бизнес-логики. Например, перейти от EF Core к Dapper или от реляционной БД к NoSQL, создав новую реализацию в Infrastructure.

3. Управление направлением зависимостей

В Clean Architecture зависимости должны направляться внутрь, к центру (Domain). Слой Application (близкий к центру) не должен зависеть от внешних, изменчивых деталей. Поэтому:

  • Domain/Application → зависит от → Интерфейсы (Abstractions)
  • Infrastructure → зависит от → Domain/Application и реализует их интерфейсы.

Если поместить CatalogRepository в Application, это создаст прямую зависимость Application от, например, DbContext и пакетов EF Core, нарушив это правило.

4. Организация кода и ответственность

  • Infrastructure — это место для всего, что связано с внешним миром: БД, сетью, файловой системой, сторонними сервисами. CatalogRepository четко попадает в эту категорию.
  • Application — это место для логики, которая использует эти внешние сервисы через абстракции для выполнения бизнес-задач.

Пример использования в Application Layer

Сервис в Application слое использует только интерфейс:

// Application Layer - Сервис приложения
public class CatalogService
{
    private readonly ICatalogRepository _repository;
    // Интерфейс может быть определен в Application или Domain

    public CatalogService(ICatalogRepository repository)
    {
        _repository = repository; // Dependency Injection абстракции
    }

    public async Task<ProductDto> GetProductDetails(int id)
    {
        var product = await _repository.GetByIdAsync(id);
        // Бизнес-логика (например, проверка доступности)
        if (product.IsDiscontinued)
            throw new ProductDiscontinuedException();
        // Маппинг на DTO
        return new ProductDto { Id = product.Id, Name = product.Name };
    }
}

Альтернативный подход: Domain Layer для интерфейсов

В некоторых строгих реализациях Clean Architecture интерфейсы репозиториев (ICatalogRepository) помещаются даже не в Application, а в самый центральный Domain Layer, поскольку они являются частью контракта домена для сохранения и получения его сущностей. Это еще больше усиливает независимость домена. В таком случае:

  • Domain: Определяет ICatalogRepository.
  • Application: Использует ICatalogRepository (зависит от Domain).
  • Infrastructure: Реализует CatalogRepository (зависит от Domain и Application).

Вывод

Вынесение CatalogRepository в Infrastructure — это сознательное архитектурное решение, которое:

  • Следует принципу Dependency Inversion, делая бизнес-логику независимой от деталей данных.
  • Четко разделяет ответственность между бизнес-правилами (Application) и технической реализацией хранения данных (Infrastructure).
  • Упрощает тестирование и поддержку, позволяя легко заменять инфраструктурные компоненты.
  • Сохраняет направление зависимостей внутрь, защищая ядро системы от изменений во внешних технологиях.

Размещение конкретных репозиториев в Infrastructure является стандартной и рекомендуемой практикой в проектах с четкой слоистой архитектурой на C#.

Почему CatalogRepository вынесен в Infrastructure, а не в Application слой? | PrepBro