【问题标题】:Download latest NuGet during run-time在运行时下载最新的 NuGet
【发布时间】:2019-04-22 09:31:48
【问题描述】:

在运行时,我想使用 .NET Core 从 NuGet 库下载最新的 DLL 并将其加载到容器中。

我正在研究一个场景,即一组依赖项已更改并且新的包版本发布到 nuget.org,之后我将不得不下载最新的包并运行一些测试。每次应用程序将验证它是否具有最新的包版本,并在必要时下载并动态加载新程序集,而无需停止应用程序。

【问题讨论】:

  • 你知道,如果你的依赖版本改变了——你需要重新编译你的应用程序,对吧?
  • 编译后的 dll 版本可能与您机器上的 Net 版本、您机器上的 Windows 版本或您机器上的微处理器不兼容。所以你必须下载源代码并动态编译以确保代码可以在你的机器上运行。
  • 假设你有一个类A,它使用来自B.dll,Version=1.0.0.0的类B。即使您在AppDomain 中下载并切换(卸载)B.dll,Version=1.0.0.0B.dll,Version=2.0.0.0,您的A 类仍然希望使用来自B.dll,Version=1.0.0.0 的类B。要改变这一点,你需要停止你的应用程序,重新编译它并再次运行。
  • @vasily.sib 这就像说当我还使用 Azure Blob Storage SDK 时使用 Newtonsoft.Json v12.0.1 会失败,因为它是针对 Newtonsoft.Json v10.0.2 编译的。我并不是说按照原始问题的要求去做是个好主意,但您所写的并不是阻止此操作的技术限制。

标签: c# .net-core dependencies nuget runtime


【解决方案1】:

我首先要说这听起来不是一个好主意。你没有解释你为什么要这样做的场景,所以我们没有办法提出更好的方法。如果它是您不希望停机的 Web 应用程序,更好的方法可能是拥有一个负载均衡器,当您发布 Web 应用程序的新版本时,配置负载均衡器以将所有新请求发送到新的包含/版本,而旧版本上的现有连接耗尽。

如果您的应用是队列侦听器,则根本不需要热加载。只要有一个应用程序,它会在您的源代码上创建一个拉取请求,以便在可用时更新 nuget 包版本号,让 CI 自动构建更改,如果测试通过,您可以自动批准/合并 PR,然后您的 CD 可以自动部署并停用以前的版本。这比自动加载新版本的风险要小,因为您冒着新版本存在错误或不兼容二进制文件的风险,现在您的应用程序将崩溃。

无论如何,如果您确实有充分的理由热重载程序集,那么在 .NET Core 上您将需要使用 AssemblyLoadContext。但是,需要这个是一个不寻常的案例,我找不到任何关于如何使用它的实际例子。我见过的所有“示例”都使用AssemblyLoadContext.Default,我认为它等同于使用单个上下文,因此不会让您加载同一程序集的不同版本。所以,如果你想走这条路,你可能不得不自己弄清楚。大量的试验和错误、调试和可能阅读 coreclr 源代码。正如您的问题的一些评论者所提到的,您还需要处理针对一个版本的依赖项编译程序集的情况,但您现在要加载不同的版本。在 .NET Framework 中使用了一种称为程序集绑定重定向的东西。大多数人使用它的方式是使用 app.config 或 web.config 文件,但这对您不起作用,因为它会在运行时更改。我确信有一个 API 可以以编程方式处理它,您还需要弄清楚这一点。我不确定 .NET Core 中的绑定重定向与 .NET Framework 相比如何/是否有所不同,所以这是您需要弄清楚的另一件事,但我确信在 google 上进行的一些好的搜索会给出你的答案。

一旦你的程序集热重载工作,你可以阅读NuGet server API并实现你自己的客户端,或者你可以使用NuGet client SDK。但是 NuGet 客户端团队的主要关注点是工具(Visual Studio 集成、dotnet cli、nuget.exe),他们只是为了方便而发布包(加上作为与 dotnet cli 和 mono 共享库的一种方式),所以没有使用 SDK 的文档。另请注意,虽然 NuGet 客户端团队试图不破坏包二进制 API,但在需要为工具实现功能和错误修复时,这是次要问题。 NuGet 客户端 SDK 跟踪 Visual Studio 版本号,它不使用语义版本控制,因此当您尝试更新到较新的 NuGet 客户端包时,您可能会发现您需要更改您的代码,否则您可能不会想到。这种情况很少见,但我通常推荐“端口和适配器”模式,这是一个很好的例子,说明它何时特别有用。至少对于 NuGet 客户端程序包,有一些人的博客文章发现了这一点,并分享了他们如何做他们需要的任何事情。否则,由于 NuGet 本身是开源的,您可以查看 NuGet 的代码以了解它如何在内部使用这些包,并将其用作帮助您弄清楚您想要做什么的指南。如果你走这条路,你将需要做 nuget 工具所做的大部分工作:

  1. 查询 NuGet 源以查找可用的包版本,然后选择要使用的版本并检查该版本是否已下载。
  2. 下载并解压包。
  3. 资产选择。特别是当一个包包含多个 TFM 的库时,您需要根据项目的 TFM 知道要使用哪一个
  4. 此阶段的 NuGet 客户端将编写 .NET SDK 使用的 project.assets.json 文件,或编辑 packages.config 和 csproj 文件,具体取决于项目使用 PackageReference 还是 packages.config。在您的情况下,这是您与程序集热重载集成的地方。

请注意,在一般情况下,上述过程或取决于您如何实现单个步骤,可能是递归的,因为包可以具有依赖关系。所以,依赖项也需要被检索,但是一个包可以有不同的依赖项,这取决于选择了哪个 TFM,所以你需要弄清楚你想要下载所有的依赖项,即使是那些在资产选择后永远不会使用的依赖项,还是您是否要先进行资产选择以最小化您下载的软件包。此外,当多个包依赖于单个包的不同版本时,您需要决定要使用哪个版本的包。

所以,这就是您需要实现的高级算法。正如我所提到的,其中大部分都没有 API 文档,其中包含有关如何实现它的示例,并且互联网上几乎没有示例(如果有的话)。就像我在第一段中写的那样,我认为这不是一个好主意。自动化你的 CI/CD 管道可能更容易,如果有必要,自动化负载均衡器的配置更改,而不是制作如此复杂的应用程序。有时编排一堆简单的应用程序比制作一个复杂的应用程序更容易。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多