.NET 热部署/取消部署捆绑代码。如何?哪个容器?

Posted

技术标签:

【中文标题】.NET 热部署/取消部署捆绑代码。如何?哪个容器?【英文标题】:.NET hot deploy/undeploy of bundled code. How to? Which container? 【发布时间】:2017-12-01 10:15:24 【问题描述】:

我们是 .NET 世界的新手,并且在 Nancy 之上构建了一个小型 C# 应用程序

我们正在寻找一种“打包”应用程序代码的方法,以便我们可以在基于 Nancy 的最小容器(或您可能建议的任何其他合适的容器)之上以编程方式对其进行热部署和取消部署

我们如何在 .NET 世界中做到这一点?

在 JVM 世界中,一种方法是打包部署在 servlet 引擎(通常是 Jetty 或 Tomcat)之上的 Web 应用程序资源 (war)。还有其他解决方案(微容器,直接使用类加载器等)。我们正在寻找一个等效的 .NET 范例。

12 月 5 日编辑

似乎有围绕构建程序集和使用 Assembly.LoadFromString 等方法的解决方案。

这看起来仍然很手动,我们正在寻找一个 C# 库/框架来帮助加载/卸载

【问题讨论】:

所以您希望无需重新启动即可更新您的 nancy 应用程序? @Evk 是的,并且以编程方式。如果它需要重新启动 - 我们希望避免这种情况 - 这也必须以编程方式完成 它是托管在 nginx\apache\iis 后面还是只使用了原始的 nancy?是完整的 .NET 还是 .NET Core? 生南希。它是一个“完整”的 .NET 应用程序,但如果有帮助,可以迁移到 .NET 核心(必须回答所有这些问题很可怕。我开始意识到 - 令人惊讶的是 - 没有明显的解决方案) 最后一个问题 :) 它是跨平台(.NET\Mono)还是你在单一平台上运行(Windows?)。 【参考方案1】:

卸载代码的唯一方法是卸载整个 AppDomain。这意味着您可能希望为每个动态加载的程序集创建一个新的 AppDomain。

此示例为您提供了如何创建新 AppDomain 以及如何调用加载到另一个 AppDomain 中的代码的起点: https://***.com/a/2648592/540832

【讨论】:

【参考方案2】:

您可以将代码加载到单独的AppDomain 中,并使用卷影复制进行热重载。假设你有这样的 nancy 应用程序:

static void Main(string[] args) 
    using (var host = new NancyHost(new Uri("http://localhost:34455"))) 
        host.Start();
        Console.WriteLine("started");
        Console.ReadKey();
    


public class SampleModule : Nancy.NancyModule 
    public SampleModule() 
        Get["/"] = _ => "Hello World!";
    

并且您希望能够在不重新启动托管过程的情况下对其进行更新。您可以这样做(警告 - 非生产就绪代码,只是示例)。像这样创建另一个应用程序:

static void Main() 
    while (true) 
        var setup = new AppDomainSetup();
        setup.ApplicationBase = @"Path to directory with your nancy app";
        setup.ShadowCopyFiles = "true";
        var domain = AppDomain.CreateDomain("Nancy", new Evidence(), setup); 
        domain.ExecuteAssembly(@"Path to your nancy app exe");
        AppDomain.Unload(domain);
    

然后启动您的第二个(主机)应用程序。它将创建新的应用程序域并在其中启动您的 nancy 应用程序。现在,您可以在主机应用程序运行时更新您的 nancy 应用程序(就在该文件夹中 - 由于卷影复制,文件未锁定)。要应用更新 - 按主机应用程序中的任意键。这将使用您的旧版本删除应用程序域并使用新版本创建新的应用程序域,而无需重新启动过程。

使用此技术,您可以例如通过FileSystemWatcher 使用您的应用程序监视目录,并在更改应用程序文件时替换应用程序域。您还可以通过在启动 nancy 主机之前先加载新的应用程序域,然后拆除旧的应用程序域,然后在新的应用程序域中启动 nancy 主机来最大限度地减少停机时间。

【讨论】:

【参考方案3】:

不幸的是,这不是 .NET 世界中的典型任务,因此您不一定会找到一个简单且广泛使用的插件解决方案。

有Managed Extensibility Framework,后来称为Microsoft.Composition,后来称为System.Composition。 请检查How to discover new MEF parts while the application is running?,因为它可能是您正在寻找的解决方案。

using System.Composition with .NET Core也有一些文章。

使用像AutoFac这样的IoC框架,自己实现一个插件系统并不难。

假设您的应用程序具有调用服务的 Nancy 模块,并且服务实现了您可能希望动态更改的实际逻辑。这使得服务本质上是一个插件。这个想法是让 IoC 为每个 http 调用返回一个更新的服务实例。

    您可以有一个作用域服务提供者\工厂,它将使用反射从刷新的程序集解析和创建服务实例。 您可以在程序集重新加载时刷新服务收集容器(或创建新的 IoC 容器)。

遗憾的是,在这两种情况下,您都必须手动检测程序集文件已更改,但这对于 FileSystemWatcher 类来说是一项微不足道的工作。

另外,在某些 IoC 库中,在运行时更新依赖项并不是一种好的做法,例如,请查看 here。

【讨论】:

【参考方案4】:

如果您使用的是 Windows/IIS,则可以使用 MSDeploy 更新您的 Web 应用程序而无需停机。请注意,它不会保留任何内存状态,因为它将在新 AppDomain 中启动新版本,而旧 AppDomain 将被卸载。

【讨论】:

不,我们没有使用 IIS。我们正在寻找动态加载代码的 C# 解决方案。

以上是关于.NET 热部署/取消部署捆绑代码。如何?哪个容器?的主要内容,如果未能解决你的问题,请参考以下文章

Python的web项目如何进行动态重载和热部署?

如何使用 Maven 将第 3 方 OSGi 捆绑包添加到部署包中?

死磕Tomcat系列——Tomcat如何做到热加载和热部署的

你知道Tomcat是如何做到热加载和热部署的吗?

maven工程使用spring-boot-devtools进行热部署,更改代码避免重启web容器

Day690.Tomcat如何实现热部署和热加载 -深入拆解 Tomcat & Jetty