我在不同的AppDomain中通过反射加载DLL时遇到了一点麻烦。
这是我的场景。
- 我有一个名为Interfaces.DLL的DLL,它只包含一个接口定义。
- Test.DLL包含了Interfaces.DLL,并定义了一个叫做Connector的类,它实现了在之前的dll中定义的接口。
- 我有一个应用程序,其中只包括接口。dll,需要使用反射加载Test.dll
- 我调用类连接器的公共方法,它返回我通过反射加载的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
那么,我如何在AppDomain中加载2个不同的Dll ?
这是我的代码:
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:Usersjferrer.GLOBALAppDataRoamingEnterpriseAppNameDllFiles"
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:Usersjferrer.GLOBALAppDataRoamingEnterpriseAppNameDllFilesTestDLL.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:Usersjferrer.GLOBALAppDataRoamingEnterpriseAppNameDllFiles" & parts(0).Trim() & ".dll"
Return Assembly.LoadFrom(myfile)
end function
更新:如果我改变
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:ProyectosBANKBankTestForm1.vb 49 20 BankTest
和原来的行为没有区别
尽管我没有直接应用@James Barras的建议,但他的评论帮助我找到了这个解决方案。所以,谢谢你花时间帮助我:)
这是一个可能的解决方案,任何人在我的情况:
- 你想要反序列化的类必须继承MarshalByRefObject
- 类中方法返回的对象必须是可序列化的
-
创建这个类:
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
-
使用下面的代码在你想加载的dll中调用一个方法:
Loader.Call(pathToDLL, ClasName,MethodName, parameters)
此解决方案在调用任何方法后卸载域。所以它不是完美的,因为如果你想调用几个方法,你将在执行时间上受到惩罚。