【发布时间】:2011-12-01 16:34:14
【问题描述】:
我正在做一个项目,我必须在运行时加载程序集(让我们称之为任务),运行任务然后能够终止整个程序集,以便可以在不中断主应用程序的情况下替换 dll。
在主应用程序中运行着许多这样的任务,有些是顺序运行的,有些是并行运行的。有时需要更新其中一项或多项任务,然后将其重新添加到队列中。目前我们正在停止整个应用程序并在其他任务处于任何阶段时中断它们,这并不理想。
我发现我必须将每个程序集加载到单独的 AppDomain 中,但事实证明在这些域中加载程序集很困难,尤其是当我需要实际运行任务并从它们接收事件时。我已经研究这个问题几天了,但仍然没有设法得到一个有效的概念证明。
我有一个用于任务的接口,其中包括一个“运行”和“杀死”方法(子)以及一个“任务步骤”、“完成”和“杀死”事件。 “taskstep”返回一个稍后缓存的对象,“完成”在整个任务完成时触发,“killed”在准备卸载时触发。整个过程也应该有两个小时的超时时间,并且在被杀死的事件上也应该有 2 分钟的超时时间,以防它被卡住,此时我希望能够卸载它,强制任何线程终止(这是无论如何“杀”应该做什么)。每个程序集可能包含多个任务,所有这些任务都应该是可加载的。
我将这些任务作为“插件”加载没有问题,但在尝试使用它们和卸载它们时我会迷路。如果我必须创建一些精心制作的包装器,那就这样吧,但我需要的东西可能吗?
我尝试从 MarshalByRefObject 继承,但我什至不知道程序集全名,除非我先加载它,然后锁定文件。我尝试从程序集的字节数组中加载。这意味着该文件未锁定,但它的副本仍保留在当前应用程序域中。这将在接下来的几个月/几年内成为问题!
For Each key As String In assemblies.Keys
Dim ad As AppDomain = AppDomainHelper.BuildChildAppDomain(AppDomain.CurrentDomain, key)
AddHandler ad.AssemblyResolve, AddressOf AssemblyResolve
_l.Add(ad)
For Each value As String In assemblies(key)
Dim item As IScanner = CType(ad.CreateInstanceAndUnwrap(key, value), IScanner)
ListBox1.Items.Add(item)
Next
Next
Private Function AssemblyResolve(sender As Object, args As ResolveEventArgs) As Assembly
Return GetType(IScanner).Assembly
End Function
【问题讨论】:
-
在自己的应用程序域中加载每个程序集似乎有什么问题?这是我过去采取的方法。
-
我不知道 Assembly.fullname 直到运行时才加载它。当我只知道它的文件路径时,如何将程序集加载到它自己的 appdomain 中,谢谢你的回复。
-
System.Reflection.AssemblyName.GetAssemblyName(路径)
-
太好了!非常感谢
-
现在我有了程序集名称(谢谢 Boo),但我很难加载扫描仪(请参阅我编辑的代码)。程序集无法解决“ResolveEventArgs 不可序列化”
标签: vb.net memory-management marshalling appdomain .net-assembly