2015-05-26 20 views
0

我有點麻煩,通過在不同的AppDomain中反射來加載DLL。加載一個DLL到不同的AppDomain和他的依賴關係

這是我的場景。

  1. 我有一個名爲Interfaces.DLL的DLL,它只包含一個接口定義。
  2. Test.DLL包含Interfaces.DLL並定義一個名爲Connector的類,該類實現了在以前的dll中定義的接口。
  3. 我有一個應用程序,其中只包含Interfaces.dll,需要使用反射加載Test.dll
  4. 我調用類連接器的公共方法,它返回通過反射加載的dll文件的DLL版本。之後,我打電話給一個Web服務來檢查我是否擁有更大版本的文件。如果沒有,我必須卸載dll,刪除文件,然後下載新文件。

問題出在步驟3.當我嘗試在不同的AppDomain中加載Test.DLL時,出現錯誤,因爲它無法在AppDomain中找到Interfaces.Dll。該消息是:

System.IO.FileNotFoundException was unhandled 
FileName=BankInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 

那麼,如何加載2個不同的DLL在AppDomain中?

這是我的代碼:

Interface.DLL

Public Interface BankInterface 
     Function getDLLVersion() As Double 
     'Other methods here 
End Interface 

Test.dll的

Public Class Connector 
    Implements BankInterfaces.BankInterface 
    Public Function getDLLVersion() As Double Implements BankInterfaces.BankInterface.getDLLVersion 
     Return 2.5 
    End Function 

MainApplication

Public Sub Main() 
    Dim domainSetup As New AppDomainSetup 
    domainSetup.ApplicationName = appDomainName 
    domainSetup.ApplicationBase = "C:\Users\jferrer.GLOBAL\AppData\Roaming\Enterprise\AppName\DllFiles\" 

    Dim LocalAppDomain As AppDomain = AppDomain.CreateDomain("BankDLL" & Guid.NewGuid.ToString.GetHashCode.ToString("x"), Nothing, domainSetup) 
    AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf CurrentDomain_AssemblyResolve 

    LocalAppDomain.CreateInstanceFrom("C:\Users\jferrer.GLOBAL\AppData\Roaming\Enterprise\AppName\DllFiles\TestDLL.dll", "TestDLL.Connector") 'This line throw the error 
    Dim conector As Type = LocalAppDomain.GetType() 

    'Irrelevant code here 
end sub 

Private Function CurrentDomain_AssemblyResolve(ByVal sender As Object, ByVal args As ResolveEventArgs) As Assembly 
    Try 
     Dim myassembly As Assembly = Assembly.Load(args.Name) 
     If Not IsNothing(myassembly) Then 
      Return myassembly 
     End If 
    Catch ex As Exception 
    End Try 

    Dim parts As String() = args.Name.Split(",") 
    Dim myfile As String = "C:\Users\jferrer.GLOBAL\AppData\Roaming\Enterprise\AppName\DllFiles\" & parts(0).Trim() & ".dll" 

    Return Assembly.LoadFrom(myfile) 
end function 

UPDATE:

如果我改變

AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf CurrentDomain_AssemblyResolve 

AddHandler LocalAppDomain.CurrentDomain.AssemblyResolve, AddressOf CurrentDomain_AssemblyResolve 

我從Visual Studio中警告:

Warning 1 Access of shared member, constant member, enum member or nested type through an instance; qualifying expression will not be evaluated. C:\Proyectos\BANK\BankTest\Form1.vb 49 20 BankTest 

還有就是沒有什麼區別原始行爲。

+1

AssemblyResolve是否不在LocalAppDomain上? –

+0

沒有必要。 AssemblyResolved是一個共享成員:https://msdn.microsoft.com/en-us/library/y6t76186.aspx – Rumpelstinsk

+1

我知道共享成員是什麼。 [程序集解析事件](https://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve(v = vs.110).aspx)不是一個。 –

回答

0

儘管我沒有直接應用@James Barras的建議,但他的評論幫助我找到了這個解決方案。所以,感謝花時間幫我:)

這是一個更多鈔票的解決方案給任何人在我的情況:

  1. 要反序列化必須從MarshalByRefObject的inheriht
  2. 通過返回的對象的類你的類中的方法必須是可序列化
  3. 創建這個類:

    Imports System.Reflection 
    
    Public Class Loader 
    Inherits MarshalByRefObject 
    Private Function CallInternal(dll As String, typename As String, method As String, parameters As Object()) As Object 
        Dim a As Assembly = Assembly.LoadFile(dll) 
        Dim o As Object = a.CreateInstance(typename) 
        Dim t As Type = o.[GetType]() 
        Dim m As MethodInfo = t.GetMethod(method) 
        Return m.Invoke(o, parameters) 
    End Function 
    Public Shared Function [Call](dll As String, typename As String, method As String, ParamArray parameters As Object()) As Object 
        Dim dom As AppDomain = AppDomain.CreateDomain("MyNewDomain") 
        Dim ld As Loader = DirectCast(dom.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, GetType(Loader).FullName), Loader) 
        Dim result As Object = ld.CallInternal(dll, typename, method, parameters) 
        AppDomain.Unload(dom) 
        Return result 
    End Function 
    End Class 
    
  4. 使用此代碼調用DLL中的方法要負載:

    Loader.Call(pathToDLL, ClasName,MethodName, parameters) 
    

該解決方案卸載域調用任何方法之後。所以它不是完美的,因爲如果你想調用幾種方法,你會在執行時間上受到懲罰。