NuGet 新特性 -- 中心化的 NuGet 包版本管理

Intro

NuGet 支持了一个可以中心化管理 NuGet 包版本的方案,我们可以在一个地方统一管理 NuGet 包的版本

Preface

在之前的版本中我们通常在每个指定包版本引用的地方会设置 NuGet 包的版本号,如果项目比较多,一个解决方案中有很多个项目的时候,很多时候就会出现重复的包版本配置.

有些项目中会使用变量来管理某些包的版本,定义变量来管理包版本,包引用处使用变量来指定包版本

而 NuGet 终于推出了一种集中管理包版本的方案,我们可以将统一的包版本定义在一个 Directory.Packages.props 文件中,在项目文件中就不需要再指定版本了,统一使用统一定义的 NuGet 包版本,这样更新包版本只需要更新这一个文件即可

Directory.Packages.props

Directory.Packages.props 和之前介绍过的 Directory.Build.props 有些类似,项目会寻找最近的一个 Directory.Packages.props

如下所示的项目结构:

Repository
 |-- Directory.Packages.props
 |-- Solution1
     |-- Directory.Packages.props
     |-- Project1
 |-- Solution2
     |-- Project2
  • Project1会使用 Repository\Solution1\ 目录下的 Directory.Packages.props
  • Project2 会使用 Repository\ 目录下的  Directory.Packages.props

Directory.Packages.props 内容示例:

<Project>
  <ItemGroup>
    <PackageVersion Include="Newtonsoft.Json" Version="13.0.1" />
  </ItemGroup>
</Project>

需要使用 PackageVersion 来定义中心化管理的包版本,对应项目中不能再包含 Version 定义了

当需要在项目文件中 override 某个包版本的时候可以使用 VersionOverride 指定要使用的版本,你可以通过定义一个 MsBuild 属性来禁用这一功能 <EnablePackageVersionOverride>false</EnablePackageVersionOverride>

Sample

来看一个使用的示例:

Directory.Packages.props

<Project>
  <PropertyGroup>
    <!-- Enable central package management -->
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="JsonSchema.Net" Version="2.3.0" />
    <PackageVersion Include="MathNet.Numerics.Signed" Version="5.0.0" />
    <PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
    <PackageVersion Include="System.CommandLine" Version="2.0.0-beta3.22114.1" />
    <PackageVersion Include="WeihanLi.Common" Version="1.0.51" />
    <PackageVersion Include="WeihanLi.Npoi" Version="2.1.0" />    
  </ItemGroup>
  <ItemGroup>
    <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
    <PackageVersion Include="FluentAssertions" Version="6.6.0" />
    <PackageVersion Include="Moq" Version="4.17.2" />
    <PackageVersion Include="xunit" Version="2.4.1" />
    <PackageVersion Include="Xunit.DependencyInjection" Version="8.5.0" />
    <PackageVersion Include="xunit.runner.visualstudio" Version="2.4.3" />
    <PackageVersion Include="coverlet.collector" Version="3.1.2" />
  </ItemGroup>
</Project>

项目文件示例:

<Project>  
  <ItemGroup>
    <PackageReference Include="JsonSchema.Net" />
    <PackageReference Include="MathNet.Numerics.Signed" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" />
    <PackageReference Include="System.CommandLine" />
    <PackageReference Include="WeihanLi.Common" />
    <PackageReference Include="WeihanLi.Npoi" />
  </ItemGroup>
</Project>

代码变更:

https://github.com/WeihanLi/dotnet-httpie/commit/a3ece1242e4edd83da36b195cd2859042dae0b5c

More

使用这一功能我们可以更方便的管理我们项目中的 NuGet 包版本,目前还没有默认启用需要等下一个版本的 SDK 发布,现在使用需要显式声明 <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>,下个版本就会默认支持,不再需要显式声明了,如果你要禁用则声明为 false 即可,目前的 SDK 中还是一个 preview feature,但是已经可用

NuGet 新特性 -- 中心化的 NuGet 包版本管理

如果同时使用多个 NuGet 源,同一个 package 存在于多个源中,则会遇到一个 NU1507 的 warning,可以结合 Package Source Mapping 来指定 package 要使用源,nuget.config 示例:

<!-- Define the package sources, nuget.org and contoso.com. -->
<!-- `clear` ensures no additional sources are inherited from another config file. -->
<packageSources>
  <clear />
  <!-- `key` can be any identifier for your source. -->
  <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  <add key="contoso.com" value="https://contoso.com/packages/" />
</packageSources>

<!-- Define mappings by adding package patterns beneath the target source. -->
<!-- Contoso.* packages will be restored from contoso.com, everything else from nuget.org. -->
<packageSourceMapping>
  <!-- key value for <packageSource> should match key values from <packageSources> element -->
  <packageSource key="nuget.org">
    <package pattern="*" />
  </packageSource>
  <packageSource key="contoso.com">
    <package pattern="Contoso.*" />
  </packageSource>
</packageSourceMapping>