不重新启动应用程序即可应用更新

11

最近我参加了一次.NET职位的面试。在所有问题中,我回答一道问题时遇到了很大的困难。希望有人能帮助我。

情景(问题):一个应用程序的第一个版本(可以是winform/wpf UI应用程序)已经发布给客户并开始使用该应用程序。但不幸的是,QA团队后来发现了当前版本的一个严重问题。现在的挑战是,我们应该能够在不强制应用程序重新启动的情况下发送和应用补丁(修复)。假设该应用程序是实时应用程序,无法重新启动以应用补丁。

就个人而言,我很难给出一个令人信服的答案,这不会影响运行应用程序时应用补丁。

答案:

感谢所有贡献的人。我已经成功解决了这个问题。不确定这是否是面试官所问的。尽管如此,我很高兴阅读有关Microsoft的ClickOnce的内容,它几乎可以实现我想要的功能。


程序的哪个部分需要修复?仅限UI吗?我猜你可以使用类似MEF的东西来卸载和重新加载更新的代码。 - eandersson
这个问题可以理解为允许更新(即覆盖文件)而不强制关闭,但应用程序不需要立即反映更改,直到选择关闭并重新打开,这在大多数情况下比在运行中的程序上应用路径并立即看到效果要容易得多。 - Grant Thomas
@eandersson:位置不明确。但是,如果它是UI修复或已在进程虚拟空间中的dll修复,您将如何处理? - sophieJ
@eandersson:我向面试官提出的一个解决方案是,如果它是一个dll文件,那么您可以将其安装在GAC上,并使配置指向最新的dll。但是,由于我忘记了配置中的属性,所以我未能扩展我的解决方案。然而,他因为dll的敏感性只能承受私有程序集,所以拒绝了我的建议。 - sophieJ
即使您可以入侵内存中加载的程序,但如果它正在处理数据,您仍然需要考虑如何保持数据一致性。如果它只是一个监控应用程序,那么可能需要将新版本作为单独的安装包。启动新版本,停止旧版本并删除它。但这在技术上并不算是“打补丁”。 - paparazzo
4个回答

4
对于当前正在运行的可执行文件,你几乎无法修改正在内存中运行的进程。
但是,从 DLL 中加载的内容更加灵活。在运行时可以动态地加载程序集,并且可以在单个应用程序中启动多个 AppDomain。一个解决方案可能是这样的:
- 你的可执行文件是一个薄壳,所有功能都通过 DLL 进行传递。 - 你的 DLL 功能是通过一个单独的 AppDomain 加载和运行的。 - 当需要打补丁时,新的 DLL 被复制进来(与现有的并排)。 - 自动或根据用户交互,在旁边启动一个新的 AppDomain 运行新的补丁。 - 在应用程序的适当时点(比如全屏切换或定时刷新),新的 AppDomain 变成“live”的。 - 旧的 AppDomain 被关闭并丢弃。
然而,这非常高级。在实际情况中,你很可能会有一个多层应用程序,具有缓存和实时数据以及许多其他考虑因素。例如,需要将应用程序的前端逻辑与缓存或数据处理部分分开,以便任何一个部分都可以被切换而不影响其余部分。
根据确切的要求,某些不太常见的技术可能会有用。先进的缓存可以允许数据层被交换掉而不影响前端显示数据的能力。命令排队或可靠的消息机制可以在业务层被切换时保持 UI 的响应性,然后新的业务层可以处理队列。如果假设一个(逻辑上的)基于服务器的应用程序,则每个层面的冗余可以允许更新一个冗余的“服务器”层面,而另一个服务器则继续处理……等等。

1
如果你从一开始就有这个需求,你可以将你的应用程序分成两个不同的应用程序——UI部分和一个服务,该服务通过单独的原子函数调用完成所有工作。很可能,你的错误出现在服务中,因此你可以随时替换该应用程序而不会影响用户体验。

0
首先,您需要知道此应用程序是否依赖于配置文件,例如xml、ini或任何形式的文本文件。如果是这样,只要它们在当前进程范围之外可编辑,补丁就可以作为配置插入。
如果第一种解决方案不可行,则第二种解决方案是查找正在运行的应用程序是否具有可靠的dll,并通过引用dll将补丁注入为依赖项,以便在调用重新启动之前暂时修复该问题。

你如何在运行时“注入补丁”?另外,你如何在配置文件中插入补丁? - Dan Puzey
你不能更改已经启动的二进制文件,唯一的方法是通过解析参数来改变预期的行为,只要正在运行的应用程序具有能力强大的公共API,该API可以从外部接收参数以改变其行为。这就像使用Python脚本来改变正在运行的应用程序的行为。 - Jegan
我向面试官提出的一个解决方案是,如果这是一个dll文件,那么可以将其安装在GAC上,并且将配置指向最新的dll。但由于我忘记了配置中的属性,因此未能进一步扩展我的解决方案。然而,由于dll的敏感性,他拒绝了这个想法,只能作为私有程序集使用。 - sophieJ
@ Dan Puzy:是的,尽管文本为基础可能是第一步。 - Jegan
@SophieJ:你考虑过在运行的应用程序上使用可用的公共API来编写Python脚本吗? - Jegan
显示剩余4条评论

-2
将旧文件重命名为其他名称(例如在文件名中添加“Old”),并将新可执行文件复制到同一文件名的位置。下次运行时,将运行新的可执行文件。

你不能重命名正在使用的东西。这只适用于在加载过程中仅被读取一次的数据文件。 - JeremyK
@JeremyK 这取决于它被如何使用,就像你在数据文件中指出的那样。即使当前正在运行,可执行文件通常也可以被很好地覆盖。 - Grant Thomas
这不是重命名某个文件,而是在已经加载到进程/虚拟空间中的dll中实现修复。想象一下交易员使用此应用程序捕获市场数据源的情景,延迟是无法承受的。这只是应用程序使用的任意示例。 - sophieJ
@sophieJ 麻烦的是,期望的最终结果是模糊不清的。 - Grant Thomas
@GrantThomas:你需要我对问题空间做更详细的阐述吗?还是你可以明确指出你发现的含糊不清之处所在。 - sophieJ
@sophieJ 我在问题的评论中解释了歧义:它是开放解释的。 - Grant Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接