繁体   English   中英

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

[英]Pain-free local development while also referencing NuGet packages

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

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

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

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

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

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

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

  • 架构(解决方案和项目组织)不能显着重组
  • 共享库将以非平凡的频率发生变化
  • 更改共享库不能强制更新任何应用程序
  • 应用程序可以引用不同版本的共享库

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

编辑我已将这些条件移到 ItemGroups 中,因为这似乎是我提到的生产代码的工作方式,并且已经提到这是 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)。 大多数用户永远不需要拉取 subrepo,因为他们没有访问 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 Standard 或 Core 项目( Properties -> Package with 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 包是不可变的)

现在在ApplicationD中,您可以指向本地存储库(%userprofile%.nuget\\packages)以获取LibraryA; 这样在每次构建 LibraryA 之后,您都会在 ApplicationD 中收到它的更新版本

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

到目前为止,我不太干净但最快的解决方案是:

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

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

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

  1. 对库进行更改
  2. 自动构建和部署以 1 递增的库版本到内部 NuGet 提要
  3. 更新使用者应用程序中的 NuGet 包

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

在ApplicationD的属性中,进入“ Reference Paths ”选项卡,添加LibraryA的输出文件夹的路径。 然后,如果您更改并构建 LibraryA,ApplicationD 的下一个构建将使用修改后的 LibraryA。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM