C# 单体仓库:代码组织实践指南
\n\n在现代 C# (.NET) 开发中,越来越多地面临在单体仓库 (monorepo) 和多仓库 (multirepo) 之间的选择问题。单体仓库是一种将所有项目、库和服务的代码存储在一个 Git 仓库中的方法。在本文中,我们将探讨如何为 C# 解决方案组织单体仓库,并介绍结构、构建配置和依赖管理的实际示例。
\n\nC# 单体仓库的优势
\n\n当您有多个相关项目时,单体仓库尤其有用:Web API、控制台应用程序、类库和测试。主要优点包括:
\n- \n
- 统一的依赖版本 — 所有项目使用相同版本的 NuGet 包和内部库。 \n
- 简化的重构 — 在一个库中更改 API 后,所有使用者立即可见。 \n
- 集中式 CI/CD — 一个流水线用于所有组件的构建、测试和部署。 \n
- 减少重复 — 通用模型、工具和配置被提取到共享项目中。 \n
然而,也需要考虑缺点:仓库大小增长、克隆时间增加(如果不使用稀疏检出),以及需要精心设计的访问权限系统。
\n\nC# 单体仓库的结构
\n\n让我们看看 .NET 项目单体仓库的典型结构。假设我们有微服务 AuthService、OrderService 和一个通用库 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\n关键元素:
\n- \n
- src/ — 包含源代码的主文件夹。 \n
- tests/ — 集成测试,如果它们不绑定到特定服务。 \n
- Directory.Build.props — 所有项目的通用 MSBuild 设置。 \n
- Directory.Packages.props — NuGet 包版本的集中管理(中央包管理模式)。 \n
- .sln — 解决方案文件,用于整合所有项目。 \n
配置集中式依赖管理
\n\n在 .NET 6+ 中,内置了对 中央包管理 (CPM) 的支持。这非常适合单体仓库。在根目录创建 Directory.Packages.props 文件:
<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\n现在,在每个 .csproj 文件中,只需指定包名,无需版本号:
<Project Sdk="Microsoft.NET.Sdk.Web">\n <PropertyGroup>\n <TargetFramework>n