【问题标题】:.NET hot deploy/undeploy of bundled code. How to? Which container?.NET 热部署/取消部署捆绑代码。如何?哪个容器?
【发布时间】: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?)。

标签: c# .net


【解决方案1】:

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

此示例为您提供了如何创建新 AppDomain 以及如何调用加载到另一个 AppDomain 中的代码的起点: https://stackoverflow.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 调用返回一个更新的服务实例。

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

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

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 不,我们没有使用 IIS。我们正在寻找动态加载代码的 C# 解决方案。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-05-02
        • 2011-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-07
        • 1970-01-01
        相关资源
        最近更新 更多