无痛的本地开发,同时还引用 NuGet 包

本文关键字:引用 NuGet 开发 无痛 | 更新日期: 2023-09-27 18:35:45

我正在尝试发布和使用类库的版本化NuGet包,同时避免本地开发的麻烦。下面是一个示例 Visual Studio 解决方案布局:

| Libraries
  | LibraryA
  | LibraryB
  | LibraryC
| Applications
  | ApplicationD
  | ApplicationE

这是一个包含共享类库和多个应用程序的单一解决方案。目前,应用程序对类库的引用是本地解决方案内引用。

我想做的是将库 (A、B、C) 发布为版本化的 NuGet 包,然后应用程序根据需要引用这些包 (D,E)。这允许对共享库的更改独立于对已部署应用程序的更新。如果没有这个,更改一个库可能会导致二进制文件在十几个或更多应用程序中发生变化,所有这些应用程序在技术上都需要进行测试。这是不可取的,使用 NuGet 进行版本控制可以解决此问题。

但是,假设我想同时更新库A和应用程序D的内容。为了在切换到 NuGet 后执行此操作,我必须对库 A 进行更改,提交它们,等待创建包,告诉应用程序 D 更新其对库 A 的引用,然后在应用程序 D 中进行测试或开发。这比简单地同时使用本地解决方案内引用要复杂得多。

对于

我的共享类库,如何获得版本化 NuGet 包的可靠性,同时保持开发简单(即使它跨越多个项目和应用程序)的更好方法是什么?我发现的唯一其他解决方案都涉及太多开销或头痛,例如必须在 NuGet 包和本地项目之间不断更改 ApplicationD 的引用。

编辑:为了澄清前提,这个问题假设以下内容:

  • 体系结构(解决方案和项目组织)无法进行重大重组
  • 共享库将以不平凡的频率变化
  • 更改共享库无法强制更新任何应用程序
  • 应用程序可以引用不同版本的共享库

无痛的本地开发,同时还引用 NuGet 包

尽管这需要一些工作,但可以通过向适当的引用添加 Condition 属性来手动编辑 .csproj 文件以设置条件引用。

编辑 我已将这些条件移动到 ItemT组中,因为似乎这就是我提到的生产代码的工作方式,并且有人提到这是 VS 2013 中可能出现的问题。

<ItemGroup Condition="'$(Configuration)' == 'Debug Local'">
    <!-- Library A reference as generated by VS for an in-solution reference, children unmodified -->
    <ProjectReference>...
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Debug NuGet'">
    <!-- Library A reference as generated by NuGet, child nodes unmodified --> 
    <Reference Include="LibraryA">...
</ItemGroup>

这将允许您在项目D&E上拥有"Debug NuGet"与"Debug Local"的配置,这些配置以不同的方式引用库。如果您随后有多个解决方案文件,这些文件的配置映射到其中项目中的相应配置,则最终用户在大多数操作中永远不会看到超过"调试"和"发布"的内容,因为这些是解决方案配置,并且只需要打开完整的解决方案来编辑 A、B 和 C 项目。

现在,至于让 A、B 和 C 项目不碍事,你可以在标记为子存储库的文件夹下设置它们(假设你使用的是支持此功能的 SCM,例如 Git)。大多数用户永远不需要拉取子存储库,因为他们不访问 ABC 项目,而是从 NuGet 获取。

维护方面,我可以保证VS不会编辑条件引用,并且在编译过程中会尊重它们 - 我已经经历了VS 2010和2013(编辑:专业版,尽管我已经深入研究了对express做同样的事情)在工作中使用相同的条件参考项目。请记住,在 VS 中,引用可以与版本无关,这使得 NuGet 成为唯一需要维护版本的地方,并且可以像任何其他 NuGet 包一样完成。虽然我充满希望,但我还没有测试 NuGet 是否会与条件引用作斗争。

编辑 谨慎的做法是,条件引用可能会导致有关缺少 DLL 的警告,但实际上不会妨碍编译或运行。

编辑对于那些仍在阅读本文的人,我现在(7/2019)听说IDE对这些更改不再那么友好,它或包管理器可能会覆盖它们。请谨慎行事,并始终阅读您的提交!

更新 .NET Core (2.x ++)

.NET Core 2.x实际上内置了此功能!

如果在项目 B 中具有对项目 A

的项目引用,并且项目 A 是具有正确包信息的 .NET 标准或核心项目(Properties -> Package Package id设置为 NuGet 包 ID),则可以在项目 B 的.csproj文件中具有常规项目引用:

<ItemGroup>
  <ProjectReference Include="..'..'A'ProjectA.csproj" />
</ItemGroup>

打包(dotnet pack)项目 B 时,由于项目 A 中的Package id,生成的.nuspec文件将使用对该包 ID 的 NuGet 依赖项以及你可能具有的其他 NuGet 引用进行设置,而不仅仅是包括生成的 DLL 文件。

<dependencies>
  <group targetFramework=".NETStandard2.0">
    <dependency id="Project.A" version="1.2.3" exclude="Build,Analyzers" />
    <dependency id="Newtonsoft.Json" version="12.0.2" exclude="Build,Analyzers" />
  </group>
</dependencies>

我知道这是一个 2 年前的帖子,但只是在面对同样的情况时找到了它。也为VS2015找到了这个,我正在测试它。我会回来相应地调整我的答案。

https://marketplace.visualstudio.com/items?itemName=RicoSuter.NuGetReferenceSwitcherforVisualStudio2015

我也遇到了类似的问题。一种有效的方法是使用本地存储库(基本上只是本地的一个文件夹)并在库中添加构建后脚本。例如:假设您需要更新 LibraryA 的实现,然后在 LibraryA 的构建后事件中包含以下 3 个步骤:

  1. 检查本地存储库是否具有该版本的软件包;如果是,则将其删除

    rd /s /q %userprofile%'.nuget'packages'LibraryA'@(VersionNumber) -Recurse -ErrorAction Ignore

  2. 创建 nuget 包

    nuget pack LibraryA.csproj

  3. 将其推送到本地存储库

    nuget push LibraryA@(VersionNumber) -Source %userprofile%'.nuget'packages

这些步骤将确保包在每次生成后始终针对该版本进行更新(我们必须这样做,因为 nuget 包是不可变的)

现在,在应用程序 D 中,您可以指向本地存储库 (%userprofile%.nuget''packages) 来获取 LibraryA;这样,在每次构建 LibraryA 之后,您将在应用程序 D 中收到它的更新版本。

PS:为了获得库的版本号,您可以使用这个:在构建后事件中确定程序集版本

不幸的是,真的没有办法两全其美。在我的公司内部,我们通过快速生成/部署过程在一定程度上缓解了它,这抵消了始终引用 NuGet 包的大部分负担。基本上,我们所有的应用程序都使用本地 NuGet 存储库中托管的同一库的不同版本。由于我们使用自己的软件来生成、部署和托管包,因此可以非常快速地更新库,然后在另一个解决方案中更新其 NuGet 包。从本质上讲,我们发现的最快的工作流程是这样的:

  1. 对库进行更改
  2. 自动生成库版本并将其递增 1 部署到内部 NuGet 源
  3. 更新使用者应用程序中的 NuGet 包

从签到更新消费项目的整个过程大约需要 3 分钟。NuGet 存储库还具有符号/源服务器,它极大地有助于调试。

在 ApplicationD 的属性中,转到"引用路径"选项卡并添加 LibraryA 输出文件夹的路径。然后,如果您更改并构建库 A,则应用程序的下一个版本将使用修改后的库 A。

完成后,不要忘记删除"引用路径"并更新引用的 NuGet 包版本。

到目前为止,

我不太干净但最快的解决方案是:

假设以下两个单独的解决方案:

VS 解决方案 1:包含作为 nuget 包发布的库:

Solution1
|_ my.first.library
|_ my.second.library

VS 解决方案 2:包含应用程序,这些应用程序使用上述一个或多个库,如PackageReference

Solution2
|_ my.first.application
|  |_ depends on nuget my.first.library (let us say v1.0.1)
|
|_ my.second.application

以防万一,我正在更改my.first.library

我按如下方式进行:

  1. 更改代码以my.first.library和重新生成
  2. 导航到my.first.library的构建输出目录(例如 <Solution1 directory>/my.first.library/bin/debug/netstandard2.0 ) 并复制.dll.pdb文件
  3. 导航到当前正在使用的 nuget 源的my.first.library 的本地目录(例如:C:'Users'user.name'.nuget'packages'my.first.library'1.0.1lib'netstandard2.0 ),并将.dll.pdb文件替换为步骤 1 中生成的文件(可能进行备份)。
  4. 更改会反映在my.first.application 中。继续工作并在需要时重复步骤 1-4

优势:

  • 完全本地化。无需辅助 nuget 饲料。
  • .csproj/.sln文件的零更改

谨慎:

虽然此解决方案提供了灵活性,但请确保在对 nuget 缓存执行操作之前清除它们,例如通过发布到 nuget 服务器。谢谢@Benrobot