1

我正在开发一个项目,我必须在运行时加载程序集(让它们调用它们的任务),运行任务,然后能够关闭整个程序集,可以在不中断主应用程序的情况下更换dll。在运行时加载,使用和卸载程序集

这些任务中有许多运行在主应用程序中,有些运行顺序,有些运行并行。偶尔需要更新一个或这些任务,然后重新添加到队列中。目前,我们正在停止整个应用程序,并在任何阶段中断其他任务,这并不理想。

我已经知道,我将不得不将每个程序集加载到单独的AppDomain中,但在这些域中加载程序集证明是困难的,特别是当我需要真正运行任务并从中接收事件时。我一直在研究这个问题几天,仍然没有设法得到一个工作证明概念。

我有一个包含'run'和'kill'方法(subs)和'taskstep','complete'和'killed'事件的任务接口。 'taskstep'返回一个对象以后被缓存,'complete'在整个任务完成时触发,'已杀死'在准备好卸载时触发。在两个小时的整个过程中也应该有一个超时,如果被阻塞的事件超时了2分钟,那么我希望能够卸载它,强制任何线程终止(这是无论如何,“杀”应该做什么)。每个程序集可能包含多个任务,所有这些任务都应该是可加载的,无法加载。

我没有问题将这些任务作为“插件”加载,但在尝试使用它们并将其卸载时丢失了。如果我必须创建一些精心制作的包装,那就这样吧,但是我甚至需要甚么可能?

我试过继承自MarshalByRefObject,但我甚至不知道程序集全名,除非我先加载它,然后锁定文件。我已经尝试从程序集的字节数组中加载。这意味着该文件没有被锁定,但它的一个副本保留在当前的appdomain中。这会在接下来的几个月/几年中出现问题!

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 
+0

什么似乎是加载每个程序集在它自己的appdomain的问题?这是我过去采取的方法。 –

+0

我不知道Assembly.fullname直到运行时没有加载它first.how我可以加载到自己的appdomain程序集当我只知道它的文件路径,谢谢你的答复。 –

+0

System.Reflection.AssemblyName.GetAssemblyName(path) –

回答

1

考虑使用Managed Extensibility Framework

它是.Net 4.0的一部分,您可以阅读简短的概述here

加载和卸载组件可以是一个非常糟糕的主意 - 东西不能按你所期望的

0

看来,(曾经试图抓住在另一个AppDomain中抛出的异常BAM你不能?!)异常是从新的(如果你愿意的话)AppDomain抛出的。这意味着ResolveEventArgs必须被序列化以跨越appdomain边界。您应该从辅助应用程序域内处理事件,因此您不必越过该边界。

所以...创建处理的决议..像一类...

Public Class AssemblyResolver 
    Inherits MarshalByRefObject 

    Public Property SearchPath As String = String.Empty 

    Public Function ResolveAssembly(sender as Object, e As ResolveEventArgs) As Assembly 

    Dim tPath As String = Path.Combine(SearchPath, e.Name & ".dll") 

    If File.Exists(tPath) Then 
     Return Assembly.LoadFrom(tPath) 
    End If 

    Return Nothing 

    End Function 

End Class 

现在从您的插件加载使用它...

Dim tPluginDomain As AppDomain = AppDomainHelper.BuildChildAppDomain(AppDomain.CurrentDomain, key) 
Dim tResolver As AssemblyResolver = tPluginDomain.CreateInstanceAndUnwrap(GetType(AssemblyResolver).Assembly.FullName, GetType(AssemblyResolver).FullName) 
AddHandler tPluginDomain.AssemblyResolve, AddressOf tResolver.ResolveAssembly 

这应该让你指出了正确的道路。
关于MSDN,所有的代码都不在我的头顶。不知道它是否会编译..期望打错/调试它。

编辑 哎呀..忘了标签解析器到插件域。固定。