Monorepository mit C#: Code-Organisation in der Praxis
\n\nIn der modernen Entwicklung mit C# (.NET) stellt sich zunehmend die Frage der Wahl zwischen einem Monorepository und einem Multirepository. Ein Monorepository ist ein Ansatz, bei dem der gesamte Code mehrerer Projekte, Bibliotheken und Dienste in einem einzigen Git-Repository gespeichert wird. In diesem Artikel analysieren wir, wie man ein Monorepository für C#-Lösungen organisiert, und betrachten praktische Beispiele für die Struktur, Build-Konfiguration und Abhängigkeitsverwaltung.
\n\nVorteile eines Monorepositorys für C#
\n\nEin Monorepository ist besonders nützlich, wenn Sie mehrere zusammenhängende Projekte haben: Web-APIs, Konsolenanwendungen, Klassenbibliotheken und Tests. Die Hauptvorteile sind:
\n- \n
- Einheitliche Abhängigkeitsversionen — alle Projekte verwenden dieselbe Version von NuGet-Paketen und internen Bibliotheken. \n
- Vereinfachtes Refactoring — eine API-Änderung in einer Bibliothek ist sofort für alle Konsumenten sichtbar. \n
- Zentralisierte CI/CD — eine einzige Pipeline für Build, Test und Deployment aller Komponenten. \n
- Reduzierung von Redundanzen — gemeinsame Modelle, Hilfsprogramme und Konfigurationen werden in Shared-Projekte ausgelagert. \n
Allerdings sind auch Nachteile zu bedenken: die wachsende Repository-Größe, längere Klonzeiten (wenn kein Sparse Checkout verwendet wird) sowie die Notwendigkeit eines durchdachten Zugriffsberechtigungssystems.
\n\nStruktur eines Monorepositorys in C#
\n\nBetrachten wir eine typische Struktur eines Monorepositorys für ein .NET-Projekt. Angenommen, wir haben die Microservices AuthService, OrderService und eine gemeinsame Bibliothek Shared.
MyMonorepo/\n├── .github/\n│ └── workflows/\n│ └── ci.yml\n├── src/\n│ ├── AuthService/\n│ │ ├── AuthService.Api/\n│ │ │ ├── Controllers/\n│ │ │ ├── Program.cs\n│ │ │ └── AuthService.Api.csproj\n│ │ └── AuthService.Tests/\n│ │ └── AuthService.Tests.csproj\n│ ├── OrderService/\n│ │ ├── OrderService.Api/\n│ │ │ └── OrderService.Api.csproj\n│ │ └── OrderService.Tests/\n│ │ └── OrderService.Tests.csproj\n│ └── Shared/\n│ ├── Shared.Models/\n│ │ └── Shared.Models.csproj\n│ └── Shared.Utils/\n│ └── Shared.Utils.csproj\n├── tests/\n│ └── IntegrationTests/\n│ └── IntegrationTests.csproj\n├── MyMonorepo.sln\n├── Directory.Build.props\n├── Directory.Packages.props\n├── .gitignore\n└── README.md\n\nSchlüsselelemente:
\n- \n
- src/ — der Hauptordner mit dem Quellcode. \n
- tests/ — Integrationstests, wenn sie nicht an einen bestimmten Dienst gebunden sind. \n
- Directory.Build.props — gemeinsame MSBuild-Einstellungen für alle Projekte. \n
- Directory.Packages.props — zentrale Verwaltung der NuGet-Paketversionen (Central Package Management-Modus). \n
- .sln — die Solution-Datei, die alle Projekte zusammenfasst. \n
Einrichtung der zentralisierten Abhängigkeitsverwaltung
\n\nIn .NET 6+ wurde die integrierte Unterstützung für Central Package Management (CPM) eingeführt. Dies ist ideal für ein Monorepository. Erstellen Sie eine Datei Directory.Packages.props im Stammverzeichnis:
<Project>\n <PropertyGroup>\n <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>\n </PropertyGroup>\n <ItemGroup>\n <PackageVersion Include="Microsoft.AspNetCore.App" Version="8.0.0" />\n <PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />\n <PackageVersion Include="xunit" Version="2.7.0" />\n </ItemGroup>\n</Project>\n\nJetzt reicht es in jeder .csproj-Datei aus, nur den Paketnamen ohne Version anzugeben:
<Project Sdk="Microsoft.NET.Sdk.Web">\n <PropertyGroup>\n <TargetFramework>n