如何使用Visual Studio 2022全局管理解决方案中所有项目的nuget包?

11

我有一个使用Visual Studio 2022创建的 .NET 6.0 解决方案,其中包含许多项目。

每个项目在 .csproj 文件中都有许多 NuGet 包引用,如下所示。

是否可以在解决方案的单个位置/全局管理所有 NuGet 包(而不是每个项目都需要管理)?

这将确保解决方案中的所有项目都使用相同版本的包(不再出现相同NuGet包的项目之间的版本冲突)。

在中央位置更新该包一次将确保所有项目都引用相同的更新版本。无需为每个项目更新包。

感谢您的帮助。

  <ItemGroup>
    <PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="10.0.1" />
    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.20.0" />
    <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2" />
    <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes.HostingStartup" Version="2.0.2" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.1" />
    <PackageReference Include="Microsoft.Azure.ServiceBus" Version="5.2.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.1">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.14.0" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.1" />
    <PackageReference Include="System.Collections" Version="4.3.0" />
    <PackageReference Include="System.Runtime" Version="4.3.1" />
  </ItemGroup>

1
为什么不使用 Visual Studio 自带的 NuGet 包管理器("工具" -> "NuGet 包管理器" -> "管理解决方案的 NuGet 包...")?其中有一个整合选项卡,可以让你在解决方案中的所有项目中保持包版本同步。 - phuzi
“Consolidate”选项卡和Sync-Package在https://dev59.com/el8d5IYBdhLWcg3weiB-#71934573问题中进行了讨论。 - Michael Freidgeim
2个回答

14

有几种方法可以实现此目的。目前(在此编辑时),只有NuGet的中央包版本管理支持管理传递性包依赖项。

手动使用.targets文件

制作一个包含您引用的所有包的.targets文件,但使用<PackageReference Update = 而不是Include =。将其包含在Directory.Build.targets文件中,以便它将应用于每个项目文件的末尾。

这样做的最大缺点是,每次向任何项目添加新的PackageReference时,您都需要记得更新.targets文件以包含一个条目来更新该包版本。

这将确保所有<PackageReference>条目统一到相同的版本。但是,它不会影响传递引用,即如果您有Project1 -> Package1 -> Package2,但只有对Package1的PackageReference,则无法影响Package2的引用版本。如果Project2 -> Package2的版本与Package1引用的版本不同,则可能会创建冲突。

使用中央包版本MSBuild SDK (CPV)

手动过程可能容易出错,因此有第三方SDK可帮助使过程更加顺畅。您可以在中央包版本(Central Package Versions)找到它。这还提供了强制要求用户不要在项目中指定版本(因为他们应该使用中央版本!),因此比使用手动技术更一致。

这种方法也无法解决传递性依赖项的问题。

使用Nuget中央包管理 (CPVM)

这是NuGet团队的解决方案。此问题在此博客文章中有所解释,或您可以在集中管理NuGet包版本中找到原始文档。

在根文件夹中命名一个名为Directory.Packages.props的文件,并通过添加以下内容启用该功能:

  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>

类似于 CPV SDK,您应该从 <PackageReference> 元素中移除所有版本,并将它们放在 Directory.Packages.props 文件中的 <PackageVersion> 元素中。如果需要覆盖版本,有两种方法:
  1. <PackageReference> 项目上添加 VersionOverride=1.2.3.4 属性。
  2. 在 .csproj 中添加 <PackageVersion Update="PackageName" Version="DifferentVersion" /> (因为 Directory.Packages.props 通过 .NET SDK 的 .props 文件导入,而该文件在 .csproj 的内容评估之前)。
这本身并不能解决传递引用的问题。您还可以另外添加 <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled> 以启用传递包的固定。这基本上是确定您直接或间接(传递) PackageReferences 中是否有匹配的 PackageVersion,如果有,则将其提升为直接引用(意味着依赖于它的任何内容也将获取固定版本)。传递固定支持至少 NuGet 6.2、VS 2022 17.2 或 .NET SDK 6.0.300。

中央软件包管理功能现已发布 - https://devblogs.microsoft.com/nuget/introducing-central-package-management/ - Dave Glassborow
1
谢谢@DaveGlassborow,我认为我现在已经更新了以反映这些变化。 - Jimmy
1
我可以推荐一个工具:https://github.com/Webreaper/CentralisedPackageConverter,它可以帮助转换现有的项目。 - gpinkas
真乱啊。花了很长时间才弄清楚这里有两套非常相似的系统。 - avolkmann

6

新的 CPM 功能被提及,但我认为我应该包含一个完整的示例。

你可以使用 NuGet 的新 "中央包管理" 功能。

示例问题:

假设你有一个 monorepo(即 VS“解决方案”或 VSCode“工作区”),其中包含多个项目。

ProjectA.csproj:

<ItemGroup>
  <PackageReference Include="Foo.Bar.Baz" Version="1.0.0" />
  <PackageReference Include="Spam.Ham.Eggs" Version="4.0.0" />
</ItemGroup>

ProjectB.csproj:

<ItemGroup>
  <PackageReference Include="Foo.Bar.Qux" Version="1.2.3" />
  <PackageReference Include="Spam.Ham.Eggs" Version="4.5.6" />
</ItemGroup>

有些项目是相同的,而其他项目则不同。您需要记住保持版本同步 - 本示例表明您忘记了这样做!

步骤1:删除版本

ProjectA.csproj:

<ItemGroup>
  <PackageReference Include="Foo.Bar.Baz" />
  <PackageReference Include="Spam.Ham.Eggs" />
</ItemGroup>

ProjectB.csproj:

<ItemGroup>
  <PackageReference Include="Foo.Bar.Qux" />
  <PackageReference Include="Spam.Ham.Eggs" Version="4.0.0" />  <!-- note version override for this project -->
</ItemGroup>

步骤2:在您的代码库根目录下添加名为Directory.Packages.props的文件

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <!-- use 'PackageVersion' rather than 'PackageReference' -->
    <PackageVersion Include="Foo.Bar.Baz" Version="1.2.3" />
    <PackageVersion Include="Foo.Bar.Qux" Version="1.2.3" />
    <PackageVersion Include="Spam.Ham.Eggs" Version="4.5.6" />
  </ItemGroup>
</Project>

步骤三:还原

对于每个项目:

  • 清除构建输出:dotnet clean
  • 还原包:dotnet restore

现在,所有您的项目都将使用您在配置文件中指定的版本。

还有更多选项,如版本覆盖和传递依赖关系固定 - 阅读文档以获取更多信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接