如何更新正在运行的c#进程(AKA热部署)的程序集?

我有一个.exe程序集和一组引用的程序集,我希望能够为其部署更新的代码。 我不需要实际更改正在运行的代码,但下次启动可执行文件时,我希望它能够获取更新的代码。 目前,当我尝试复制正在运行的文件时,我收到有关另一个进程正在使用的.exe的错误。

总结一下; 如何在使用.exe时更新代码?

这很容易做到。 您可以重命名该文件,Windows对句柄有锁定,而不是文件的目录条目。 现在您只需复制更新即可。 剩下要做的就是在你的应用再次启动后摆脱重命名的文件。 如有必要。

我不认为这是可能的。 例如,在零停机时部署asp.net应用程序时,最佳做法是使用负载均衡器,以便您可以删除一个实例,更新它,然后取下另一个实例进行更新。

在使用时,您无法更新程序集。 此类情况的最佳选择是制作一个小型可执行文件,它可以执行程序集的卷影副本,并从新位置启动它们。

这样,当用户启动程序时,您可以从部署站点进行卷影复制(本地),这可以始终被覆盖。

ClickOnce为您提供了一些选择。 有一个“应用程序启动后更新 ”的更新策略 。

对于更复杂的方案,有System.Deployment命名空间 。 例如,您可以定期轮询应用程序中的更新。

此类将重命名当前运行的可执行文件,如果它完成无exception,您只需编写新的可执行文件,然后重新启动,例如:

Ourself.Rename(); // Download or copy new version File.Copy(newVersion, Ourself.FileName()); // Launch new version System.Diagnostics.Process.Start(Ourself.FileName()); // Close current version Close(); // Exit(); 

够容易吗?

 class Ourself { public static string FileName() { Assembly _objParentAssembly; if (Assembly.GetEntryAssembly() == null) _objParentAssembly = Assembly.GetCallingAssembly(); else _objParentAssembly = Assembly.GetEntryAssembly(); if (_objParentAssembly.CodeBase.StartsWith("http://")) throw new IOException("Deployed from URL"); if (File.Exists(_objParentAssembly.Location)) return _objParentAssembly.Location; if (File.Exists(System.AppDomain.CurrentDomain.BaseDirectory + System.AppDomain.CurrentDomain.FriendlyName)) return System.AppDomain.CurrentDomain.BaseDirectory + System.AppDomain.CurrentDomain.FriendlyName; if (File.Exists(Assembly.GetExecutingAssembly().Location)) return Assembly.GetExecutingAssembly().Location; throw new IOException("Assembly not found"); } public static bool Rename() { string currentName = FileName(); string newName = FileName() + ".ori"; if (File.Exists(newName)) { File.Delete(newName); } File.Move(currentName, newName); return true; } } 

只是一个想法:尝试MEF和[导入[“ http:// someRemoteResource ”]]

以下内容如何:

  1. 将exe部署到更新文件夹。
  2. 每当应用程序启动时,它都会检查更新文件夹。
  3. 如果它不为空,则执行复制程序
  4. 然后,复制程序将使用更新文件夹中的那个替换现有的exe
  5. 删除更新文件夹中的任何内容
  6. 然后重新启动exe

最好的想法是已经建议的其他答案之一……比如使用MEF和/或ClickOnce重新组合。 但是,这些解决方案无法帮助您实现“此部署”。 它们要求您对exe进行更改,或者创建引导带可执行文件,这只会帮助您进行下一次部署。

对于这个部署,你可以尝试这样做(我以前从未这样做过,但理论上它可以工作):

  1. 将您的新dll复制到某个子文件夹
  2. 将命令行xcopy命令添加到RunOnce注册表项,以将新dll从子文件夹复制到您希望它去的最终exe文件夹。
  3. 重启。

RunOnce键包含命令行命令,这些命令在重新引导时运行一次,然后从注册表中删除,以便它们不再运行。 这就是InstallShield允许您在其他应用程序使用时覆盖某些dll的方式。