Монорепозиторий с C#: организация кода на практике

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Монорепозиторий с C#: организация кода на практике

Монорепозиторий (monorepo) — это подход к управлению исходным кодом, при котором все проекты компании или команды хранятся в одном репозитории. В мире C# и .NET этот подход становится всё популярнее благодаря упрощению совместной разработки, унификации версий зависимостей и централизованному CI/CD. Однако без правильной организации кода монорепозиторий может превратиться в хаос. В этой статье мы разберём практические приёмы организации C#-кода в монорепозитории: от структуры папок до настройки сборки.

1. Структура папок: основа порядка

Первый шаг к успешному монорепозиторию — продуманная иерархия каталогов. Рекомендуется придерживаться конвенции, где каждый проект лежит в отдельной папке, а общие компоненты вынесены в src/shared. Пример базовой структуры:

/monorepo
├── src/
│   ├── shared/
│   │   ├── CommonLib/          # Общие утилиты, DTO, интерфейсы
│   │   └── LoggingLib/         # Логирование
│   ├── services/
│   │   ├── AuthService/        # Микросервис аутентификации
│   │   └── OrderService/       # Микросервис заказов
│   └── apps/
│       ├── WebApi/             # Основное веб-приложение
│       └── ConsoleApp/         # Консольный инструмент
├── tests/
│   ├── unit/
│   │   ├── CommonLib.Tests/
│   │   └── AuthService.Tests/
│   └── integration/
│       └── IntegrationTests/
├── docs/
├── scripts/
├── .gitignore
├── Directory.Build.props
└── global.json

Ключевые моменты:

  • src/ — исходный код всех проектов.
  • shared/ — библиотеки, используемые несколькими проектами.
  • services/ — микросервисы или модули.
  • apps/ — конечные приложения (Web API, Console, Blazor).
  • tests/ — тесты, изолированные от исходного кода.

Такая структура позволяет легко находить код, избегать циклических зависимостей и упрощает настройку CI/CD.

2. Управление проектами с помощью Directory.Build.props

В монорепозитории часто возникает необходимость задать общие настройки для всех проектов: версии .NET, общие пакеты, правила анализа кода. Вместо дублирования в каждом .csproj используйте файл Directory.Build.props в корне репозитория. Пример:

<Project>
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="SonarAnalyzer.CSharp" Version="9.*" />
  </ItemGroup>
</Project>

Теперь каждый дочерний проект автоматически наследует эти настройки. Если нужно переопределить для конкретного проекта, просто добавьте свойства в его .csproj — они имеют приоритет.

Дополнительно можно создать Directory.Build.targets для общих целей сборки (например, копирование файлов после билда).

3. Управление зависимостями: централизованный подход

Одна из главных проблем монорепозитория — конфликт версий пакетов. В .NET 8 появилась встроенная поддержка централизованного управления пакетами (Central Package Management, CPM). Для этого создайте файл Directory.Packages.props в корне:

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
    <PackageVersion Include="Serilog" Version="3.1.1" />
    <PackageVersion Include="xunit" Version="2.7.0" />
  </ItemGroup>
</Project>

Теперь в каждом .csproj достаточно указать только имя пакета без версии:

<ItemGroup>
  <PackageReference Include="Serilog" />
  <PackageReference Include="xunit" />
</ItemGroup>

Версии будут подтянуты из центрального файла. Это гарантирует, что все проекты используют одинаковые версии зависимостей, и упрощает обновление.

4. Сборка и CI/CD: автоматизация без боли

Для сборки монорепозитория удобно использовать solution-файлы (.sln). Создайте один или несколько solution-файлов, группируя проекты по логике (например, Monorepo.sln для всех проектов, Services.sln только для микросервисов).

Пример команды для восстановления и сборки всех проектов:

dotnet restore Monorepo.sln
dotnet build Monorepo.sln --configuration Release

В CI/CD (например, GitHub Actions) можно настроить триггеры на изменения в конкретных папках, чтобы не пересобирать весь репозиторий. Пример конфигурации для YAML:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '8.0.x'
      - name: Restore
        run: dotnet restore Monorepo.sln
      - name: Build
        run: dotnet build Monorepo.sln --configuration Release --no-restore
      - name: Test
        run: dotnet test Monorepo.sln --configuration Release --no-build

Для оптимизации можно добавить кэширование ~/.nuget/packages и использовать

Блоги

Рекомендаций по книгам