I'm having a bit trouble to load a DLL by reflection in a different AppDomain.
This is my scenario.
The problem is on step 3. When i try to load Test.DLL in a different AppDomain, i get an error because it cannot find Interfaces.Dll in the AppDomain. The message is:
System.IO.FileNotFoundException was unhandled
FileName=BankInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
So, how can I load 2 different Dll in a AppDomain?
This is my code:
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:
If I change
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf CurrentDomain_AssemblyResolve
to
AddHandler LocalAppDomain.CurrentDomain.AssemblyResolve, AddressOf CurrentDomain_AssemblyResolve
I get a warning from 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
And there is no difference between the original behaviour.
Despite I have not applied directly the suggestions of @James Barras, his comments help me to find this solutions. So, thanks for take the time to help me :)
This is a posible solution to anyone in my situation:
Create this class:
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
Use this code to call a method inside the dll you want to load:
Loader.Call(pathToDLL, ClasName,MethodName, parameters)
This solution unload the domain after you call any method. So it is not perfect, because if you want to call several methods, you will be penalized on execution time.