DLL de carga dinámica .Net
Estoy tratando de escribir algún código que me permita cargar dinámicamente archivos DLL en mi aplicación, dependiendo de la configuración de la aplicación. La idea es que la base de datos a la que se accede esté configurada en la configuración de la aplicación y luego esto carga el archivo DLL apropiado y lo asigna a una instancia de una interfaz para que acceda mi aplicación.
Este es mi código en este momento:
Dim SQLDataSource As ICRDataLayer
Dim ass As Assembly = Assembly. _
LoadFrom("M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\SQLServer.dll")
Dim obj As Object = ass.CreateInstance(GetType(ICRDataLayer).ToString, True)
SQLDataSource = DirectCast(obj, ICRDataLayer)
MsgBox(SQLDataSource.ModuleName & vbNewLine & SQLDataSource.ModuleDescription)
Tengo mi interfaz (ICRDataLayer) y el SQLServer.dll contiene una implementación de esta interfaz. Solo quiero cargar el ensamblado y asignarlo al objeto SQLDataSource.
El código anterior simplemente no funciona. No se lanzan excepciones, incluso el Msgbox no aparece. Hubiera esperado que al menos el cuadro de mensaje apareciera sin nada, ¡pero incluso esto no sucede!
¿Hay alguna manera de determinar si el ensamblado cargado implementa una interfaz específica? Intenté lo siguiente, ¡pero esto tampoco parece hacer nada!
For Each loadedType As Type In ass.GetTypes
If GetType(ICRDataLayer).IsAssignableFrom(loadedType) Then
Dim obj1 As Object = ass.CreateInstance(GetType(ICRDataLayer).ToString, True)
SQLDataSource = DirectCast(obj1, ICRDataLayer)
End If
Next
EDITAR: Nuevo código de los ejemplos de Vlad:
Module CRDataLayerFactory
Sub New()
End Sub
' class name is a contract,
' should be the same for all plugins
Private Function Create() As ICRDataLayer
Return New SQLServer()
End Function
End Module
Arriba está el Módulo en cada DLL, convertido del ejemplo C # de Vlad.
A continuación se muestra mi código para traer la DLL:
Dim SQLDataSource As ICRDataLayer
Dim ass As Assembly = Assembly. _
LoadFrom("M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\SQLServer.dll")
Dim factory As Object = ass.CreateInstance("CRDataLayerFactory", True)
Dim t As Type = factory.GetType
Dim method As MethodInfo = t.GetMethod("Create")
Dim obj As Object = method.Invoke(factory, Nothing)
SQLDataSource = DirectCast(obj, ICRDataLayer)
EDITAR: Implementación basada en el código de Paul Kohler
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetTypes
Dim s As System.Type() = assemblyType.GetInterfaces
For Each ty As System.Type In s
If ty.Name.Contains("ICRDataLayer") Then
MsgBox(ty.Name)
plugin = DirectCast(Activator.CreateInstance(assemblyType), ICRDataLayer)
MessageBox.Show(plugin.ModuleName)
End If
Next
Me sale el siguiente error con este código:
No se puede convertir el objeto de tipo 'SQLServer.CRDataSource.SQLServer' para escribir 'DynamicAssemblyLoading.ICRDataLayer'.
La DLL real está en un proyecto diferente llamado SQLServer en la misma solución que mi código de implementación. CRDataSource es un espacio de nombres y SQLServer es el nombre de clase real de la DLL. La clase SQLServer implementa ICRDataLayer, por lo que no entiendo por qué no podría lanzarlo. El nombre es significativo aquí, no hubiera pensado que sería.
Código de trabajo final
Contenido de PluginUtility:
enter code here Public Shared Function GetInstances1(Of Type)(ByVal baseDir As String, ByVal searchPattern As String) As System.Type()
Dim tmpInstances As New List(Of Type)
Try
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetTypes
Dim s As System.Type() = assemblyType.GetInterfaces
Return s.ToArray()
Next
Next
Catch exp As TargetInvocationException
If (Not exp.InnerException Is Nothing) Then
Throw exp.InnerException
End If
End Try
End Function
Código para cargar la DLL:
enter code here
Dim basedir As String = "M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\"
Dim searchPattern As String = "*SQL*.dll"
Dim plugin As CRDataLayer.ICRDataLayer
Try
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetExportedTypes
If assemblyType.GetInterface("CRDataLayer.ICRDataLayer") IsNot Nothing Then
plugin = DirectCast(Activator.CreateInstance(assemblyType), CRDataLayer.ICRDataLayer)
MessageBox.Show(plugin.ModuleDescription)
End If
Next
Next
Catch exp As TargetInvocationException
If (Not exp.InnerException Is Nothing) Then
Throw exp.InnerException
End If
Catch ex As Exception
MsgBox(ex.Message)
Clipboard.SetText(ex.Message)
End Try