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

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

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

Начать курс

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

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

1. Преимущества монорепозитория для .NET

Монорепозиторий особенно полезен для команд, работающих над несколькими связанными .NET-проектами: микросервисами, веб-приложениями, библиотеками классов. Основные плюсы:

  • Единая версия зависимостей — все проекты используют одинаковые версии NuGet-пакетов, что исключает конфликты.
  • Упрощённый рефакторинг — изменение общего интерфейса или модели данных сразу применяется ко всем потребителям.
  • Общая история Git — атомарные коммиты, которые затрагивают несколько проектов, видны в одном месте.
  • Централизованная CI/CD — один pipeline для сборки, тестирования и деплоя всех компонентов.

Для C# монорепозиторий строится вокруг единого .sln-файла (solution), который ссылается на все проекты. Это позволяет использовать встроенные средства Visual Studio и .NET CLI для управления зависимостями.

2. Структура монорепозитория для C#

Рассмотрим типовую структуру монорепозитория для .NET-решения. Она может выглядеть так:

MyCompany/
├── src/
│   ├── MyCompany.Common/          # Общая библиотека
│   │   ├── MyCompany.Common.csproj
│   │   └── ...
│   ├── MyCompany.WebApi/          # Веб-API
│   │   ├── MyCompany.WebApi.csproj
│   │   └── ...
│   └── MyCompany.BackgroundJob/   # Фоновый сервис
│       ├── MyCompany.BackgroundJob.csproj
│       └── ...
├── tests/
│   ├── MyCompany.Common.Tests/
│   ├── MyCompany.WebApi.Tests/
│   └── MyCompany.BackgroundJob.Tests/
├── docs/                         # Документация
├── scripts/                      # Скрипты для CI/CD
├── .gitignore
└── MyCompany.sln                 # Единое решение

Ключевые элементы этой структуры:

  • src/ — папка с исходным кодом. Каждый проект — отдельная папка со своим .csproj-файлом.
  • tests/ — папка с тестами. Названия тестовых проектов повторяют названия основных с суффиксом .Tests.
  • docs/ — документация (README, архитектурные решения).
  • scripts/ — скрипты для автоматизации сборки или деплоя.
  • MyCompany.sln — единый файл решения, который включает все проекты.

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

3. Настройка единого решения и общих зависимостей

Для создания монорепозитория в .NET используйте команду dotnet new sln, а затем добавляйте проекты:

# Создаём корневую папку и переходим в неё
mkdir MyCompany && cd MyCompany

# Создаём пустой файл решения
dotnet new sln -n MyCompany

# Создаём структуру папок
mkdir src tests docs scripts

# Создаём проекты
dotnet new classlib -n MyCompany.Common -o src/MyCompany.Common
dotnet new webapi -n MyCompany.WebApi -o src/MyCompany.WebApi
dotnet new console -n MyCompany.BackgroundJob -o src/MyCompany.BackgroundJob

# Добавляем проекты в решение
dotnet sln add src/MyCompany.Common/MyCompany.Common.csproj
dotnet sln add src/MyCompany.WebApi/MyCompany.WebApi.csproj
dotnet sln add src/MyCompany.BackgroundJob/MyCompany.BackgroundJob.csproj

Теперь добавим ссылку на общую библиотеку из веб-API:

cd src/MyCompany.WebApi
dotnet add reference ../MyCompany.Common/MyCompany.Common.csproj

Пример кода общей библиотеки (MyCompany.Common):

// src/MyCompany.Common/Models/User.cs
namespace MyCompany.Common.Models;

public class User
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
}

Пример использования в веб-API (MyCompany.WebApi):

// src/MyCompany.WebApi/Controllers/UsersController.cs
using Microsoft.AspNetCore.Mvc;
using MyCompany.Common.Models;

namespace MyCompany.WebApi.Controllers;

[ApiController]
[Route("[controller]")]
public class UsersController : ControllerBase
{
    [HttpGet]
    public IActionResult GetUsers()
    {
        var users = new List<User>
        {
            new User { Id = 1, Name = "Alice", Email = "alice@example.com" },
            new User { Id = 2, Name = "Bob", Email = "bob@example.com" }
        };
        return Ok(users);
    }
}

Такая настройка гарантирует, что все проекты используют одну и ту же версию MyCompany.Common. Любое изменение в библиотеке сразу отражается на всех потребителях.

4. Работа с Git и CI/CD в монорепозитории

Для эффективной работы с монорепозиторием в .NET используйте следующие практики:

  • Git Flow или Trunk-Based Development — выберите один подход для всей команды. В монорепозитории особенно удобен Trunk-Based, когда изменения мержатся в основную ветку несколько раз в день.
  • .gitignore для .NET — обязательно добавьте стандартный .gitignore для C# (bin, obj, .vs, NuGet-пакеты).
  • CI/CD с фильтрацией — настройте pipeline так, чтобы сборка запускалась только для изменённых проектов. Например, в GitHub Actions можно использовать paths-filter.

Пример YAML для GitHub Actions, который запускает тесты только для изменённых проектов:

                

Блоги

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