帮助官方 NuGet 解掉 Bug,制作绝对不会传递依赖的 NuGet 包

栏目: ASP.NET · 发布时间: 5年前

内容简介:如果你希望做一个 NuGet 工具包,那么这个包一定不能作为依赖传递给下一个包。典型的例子,做一个生成版本号的工具 NuGet 包,或者做一个代码分析器。本文将解决 NuGet 的几个坑,真正做到绝对没有的依赖传递。如果你使用了 GitVersion 这款 NuGet 包来自动修改你的版本号,那么你可能会遇到这个问题。

如果你希望做一个 NuGet 工具包,那么这个包一定不能作为依赖传递给下一个包。典型的例子,做一个生成版本号的工具 NuGet 包,或者做一个代码分析器。

本文将解决 NuGet 的几个坑,真正做到绝对没有的依赖传递。

我们遇到了什么问题

如果你使用了 GitVersion 这款 NuGet 包来自动修改你的版本号,那么你可能会遇到这个问题。 GitTools/GitVersion: Easy Semantic Versioning (http://semver.org) for projects using Git

假想我们希望开发一个 NuGet 包 Walterlv.PackageDemo.A。另一位小伙伴想要使用我 A 包的功能做一个 Walterlv.PackageDemo.B 包。于是其他小伙伴可以安装 B 包去做自己的项目 C。

那么,除非我在 B 包安装完之后,明确在 B 的 csproj 文件中写以下代码,否则 B 包发布出去后,安装 B 包的项目 C 就会同时安装上 A 包。

<ItemGroup>
  <PackageReference Include="Walterlv.PackageDemo.A" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

显然,由于 A 是个 工具 包,只是为了给安装了 A 的 B 包提供版本号或其他编译期功能的。C 不需要这样的功能!

然而我们希望做出来的 A 包具备这样的特点:

  1. 小伙伴给 B 安装 A 包的时候,不用额外为 A 包写配置依赖的代码;
  2. 小伙伴为 C 安装 B 的时候,不会出现 A 乱入的情况。

如果你依然对这样的问题存有疑惑,可以阅读以下文章,这是切实的例子。

官方提供的解决方案

官方在非常早期的 2.7 版本就提供了 developmentDependency 属性,可以在 nuspec 文件中写。但实际上这个属性在后面版本的 NuGet 开发中就丢掉了。不生效。

官方提供了 IsTool 属性可以使用,但这依然不能阻止 B 安装了 A 包之后,C 包被迫安装 A 包的问题。

我试图寻找的解决方案

我们创建一个项目 Walterlv.PackageDemo.A 模拟前面提到的包 A,创建一个项目 Walterlv.PackageDemo.B 模拟前面提到的包 B,创建一个项目 Walterlv.ProjectDemo.C 模拟前面的项目 C。注意,实际场景中,这三个项目通常在不同的仓库中,由不同的开发者开发。

帮助官方 NuGet 解掉 Bug,制作绝对不会传递依赖的 NuGet 包

不过,为了方便起见,我打算直接在一个解决方案中模拟这样的效果:

帮助官方 NuGet 解掉 Bug,制作绝对不会传递依赖的 NuGet 包

我在 A 中试图创建一个 build\Walterlv.PackageDemo.A.props 文件,并在里面写一些阻止 A 被依赖的代码。

<Project>

  <ItemGroup>
    <PackageReference Update="Walterlv.PackageDemo.A" PrivateAssets="All" />
  </ItemGroup>

</Project>

当这段代码被 Visual Studio 编译的时候,一切符合预期。然而使用命令行编译的时候,就不按照预期工作了。

我提供的强力解决方案

为 A 项目添加强力去除依赖

我们需要为 A 项目添加一个 build\Walterlv.PackageDemo.A.targets 文件。这份文件会在其他项目安装 A 并且编译的时候执行。

里面的内容为:

<Project>

  <Target Name="ForceWalterlvDemoPrivateAssets" BeforeTargets="CollectPackageReferences">
    <ItemGroup>
      <PackageReference Update="Walterlv.PackageDemo.A" PrivateAssets="All" />
    </ItemGroup>
  </Target>

</Project>

就是在 CollectPackageReferences 之前,即 MSBuild 开始编译之前收集 NuGet 引用之前执行。将 Walterlv.PackageDemo.A 的所有内容设为私有依赖。

最关键的就是 PrivateAssets="All" 这一句,将所有内容设为私有依赖。阅读 如何创建一个基于 MSBuild Task 的跨平台的 NuGet 工具包 可以了解更多关于 NuGet 打包相关的知识。

帮助官方 NuGet 解掉 Bug,制作绝对不会传递依赖的 NuGet 包 ▲ 项目的结构

为了通用一点,我取名为 Package.targets 文件,并在 A 项目编译的时候改名为 Walterlv.PackageDemo.A.targets。

以下是 A 项目的 csproj 文件,包含将 Package.targets 在打包 NuGet 包时改名的部分。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
  </PropertyGroup>

  <ItemGroup>
    <None Include="Assets\build\Package.targets" Pack="True" PackagePath="build\$(PackageId).targets" />
  </ItemGroup>

</Project>

在 B 项目中进行测试

本地调试当然用不着推送到 https://nuget.org 。我们本地新建一个源,专门用于调试。

在 “工具 -> 选项 -> NuGet 包管理器” 中,我们可以设置 NuGet 源:

帮助官方 NuGet 解掉 Bug,制作绝对不会传递依赖的 NuGet 包 ▲ 添加调试用的 NuGet 源

我们把刚刚 A 项目的输出目录填进去添加一个新的源。于是我们就能在 B 项目中安装 A 包了。

于是 B 项目的 csproj 文件全文内容如下:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Walterlv.PackageDemo.A" Version="1.0.0" />
  </ItemGroup>

</Project>

现在编译 B 项目,我们能得到 B 的 NuGet 包。打开 B 项目的 NuGet 包后,我们发现其中没有对 A 的依赖。这种情况下其他项目安装 B 是不会出现 A 项目的额外引用的。

帮助官方 NuGet 解掉 Bug,制作绝对不会传递依赖的 NuGet 包

使用 Visual Studio 编译和命令行编译效果是一样的。至此,我们的问题就是真的解决了。

本文会经常更新,请阅读原文: https://walterlv.github.io/post/prevent-nuget-package-been-depended.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

帮助官方 NuGet 解掉 Bug,制作绝对不会传递依赖的 NuGet 包 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://walterlv.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

.NET本质论 第1卷:公共语言运行库

.NET本质论 第1卷:公共语言运行库

博克斯 (BoxDon) / 张晓坤 / 中国电力出版社 / 2004-1 / 48.00元

本书由10章组成,探讨了CLR即公共语言运行库,涵盖了基本类型、实例、方法调用和消息、AppDomain、安全、以及CLR外部世界。一起来看看 《.NET本质论 第1卷:公共语言运行库》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换