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,所有的代碼都不在我的頭頂。不知道它是否會編譯..期望打錯/調試它。

編輯 哎呀..忘了標籤解析器到插件域。固定。