I am trying to write code that will allow me to dynamically load DLLs into my application, depending on the configuration of the application. The idea is that an accessible database is set in the application settings, and then it loads the corresponding DLL and assigns it to an interface instance for access of my application.
This is my code at the moment:
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)
I have my interface (ICRDataLayer), and SQLServer.dll contains an implementation of this interface. I just want to load the assembly and assign it to the SQLDataSource object.
The above code just doesn't work. There are no exceptions, even Msgbox does not appear. I would expect that at least nothing has appeared in the message box, but even this does not happen!
Is there a way to determine if a loaded assembly implements a specific interface. I tried below, but that also does nothing!
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
EDIT: new code from Vlad's examples:
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
Above is the module in each DLL, converted from the Vlad C # example.
Below is my code to call the 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)
EDIT: Paul Kohler Code Based Implementation
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
I get the following error with this code:
Cannot pass an object of type "SQLServer.CRDataSource.SQLServer" to enter "DynamicAssemblyLoading.ICRDataLayer".
The actual DLL is in another project called SQLServer in the same solution as my implementation code. CRDataSource is the namespace, and SQLServer is the actual name of the DLL class. The SQLServer class implements ICRDataLayer, so I donโt understand why it cannot use it. Whether the designation is significant here, I would not have thought what it would be.
Final working code
Plugin Content:
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
Code for loading the 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