我有一个.exe程序集和一组引用的程序集,我希望能够为其部署更新的代码。我不需要实际更改正在运行的代码,但下次启动可执行文件时,我希望它能够获取更新的代码。目前,当我尝试复制正在运行的文件时,我收到有关其他进程正在使用的.exe的错误。
总结;如何在使用.exe时更新代码?
答案 0 :(得分:18)
很容易做到。您可以重命名该文件,Windows在句柄上有锁,而不是文件的目录条目。现在您可以毫无问题地复制更新。剩下要做的就是在你的应用再次启动后摆脱重命名的文件。如有必要。
答案 1 :(得分:3)
我不认为这是可能的。例如,在部署没有停机时间的asp.net应用程序时,最佳做法是使用负载均衡器,这样您就可以删除一个实例,更新它,然后取下另一个实例进行更新。
答案 2 :(得分:2)
使用时无法更新装配体。此类情况的最佳选择是制作一个小型可执行文件,用于执行程序集的卷影副本,并从新位置启动它们。
这样,当用户启动程序时,您可以从部署站点进行卷影复制(本地),这可以随时被覆盖。
答案 3 :(得分:2)
ClickOnce为您提供了一些选择。应用程序启动后有一个update strategy“更新。”
对于更复杂的方案,有System.Deployment namespace。例如,您可以定期轮询应用程序中的更新。
答案 4 :(得分:2)
此类将重命名当前运行的可执行文件,如果它完成无异常,您只需编写新的可执行文件,然后重新启动,例如:
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;
}
}
答案 5 :(得分:1)
只是一个想法:尝试MEF和[导入[“http://someRemoteResource”]]
答案 6 :(得分:1)
以下内容如何:
答案 7 :(得分:1)
最好的想法是已经建议的其他答案之一......就像使用MEF和/或ClickOnce重新组合一样。但是,这些解决方案无法帮助您实现“此部署”。它们要求您对exe进行更改,或者创建一个引导带可执行文件,这只会帮助您进行下一次部署。
对于此部署,您可以尝试这样做(我以前从未这样做过,但理论上它可以工作):
RunOnce键包含命令行命令,这些命令在重新启动时运行一次,然后从注册表中删除,以便它们不再运行。这就是InstallShield允许您在其他应用程序使用时覆盖某些dll的方式。
答案 8 :(得分:0)
如果您想替换之前更新过的assembly
,则有可能。我有一个应用程序,用户可以下载新的HtCore.dll
。下载后,我将其重命名为HtCore.dll_new
。在应用程序启动时,将替换库,如下所示:
修改您的App.cs
public App()
{
try
{
var htCore = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "HtCore.dll");
if (File.Exists($"{htCore}_new"))
{
File.Copy(htCore, $"{htCore}_backup", true);
File.Delete(htCore);
File.Move($"{htCore}_new", htCore);
File.Delete($"{htCore}_new");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}