.Net dynamically load DLL

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 
+6
reflection dll assemblies
source share
3 answers

Version 2 - This sample loads the DLL from the current directory. There are 2 projects, 1 project of the console application and the project โ€œmoduleโ€ (the module โ€œcopiesโ€ its DLL into the working directory of the console application).

The example below simply demonstrates the dynamic loading of a DLL that implements the interface. The IModule simply reports its name. PlugInUtility.GetInstances(Of IModule)(Environment.CurrentDirectory, "*.Module.dll") will instantiate any IModule instance found in the DLL in the current directory ending in ..Module.dll. This is a mirrored version of VB.NET directly from a Mini SQL query.

Keeping in mind something like:

 Dim modules As IModule() = PlugInUtility.GetInstances(Of ICRDataLayer)(Environment.CurrentDirectory, "*.Server.dll") 

Meets your requirement. Then you just need to choose which one to execute!

The code:

In the "VB.LoaderDemo Colsole App"

 ' IModule.vb Public Interface IModule Property ModuleName() As String End Interface ' PlugInUtility.vb Imports System.IO Imports System.Reflection Public Class PlugInUtility Public Shared Function GetInstances(Of T)(ByVal baseDir As String, ByVal searchPattern As String) As T() Dim tmpInstances As New List(Of T) Try Dim file As String For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly) Dim assemblyType As Type For Each assemblyType In Assembly.LoadFrom(file).GetTypes() If (Not assemblyType.GetInterface(GetType(T).FullName) Is Nothing) Then tmpInstances.Add(DirectCast(Activator.CreateInstance(assemblyType), T)) End If Next Next Catch exp As TargetInvocationException If (Not exp.InnerException Is Nothing) Then Throw exp.InnerException End If End Try Return tmpInstances.ToArray() End Function End Class ' MainModule.vb Module MainModule Sub Main() Dim plugins As IModule() = PlugInUtility.GetInstances(Of IModule)(Environment.CurrentDirectory, "*.Module.dll") Dim m As IModule For Each m In plugins Console.WriteLine(m.ModuleName) Next End Sub End Module 

In the "Sample1 DLL" (links "VB.LoaderDemo" for IModule)

 Imports VB.LoaderDemo Public Class MyModule1 Implements IModule Dim _name As String Public Sub New() _name = "Sample 1, Module 1" End Sub Public Property ModuleName() As String Implements IModule.ModuleName Get Return _name End Get Set(ByVal value As String) _name = value End Set End Property End Class 

Output:

 > Sample 1, Module 1 
+2
source share

Is the type ICRDataLayer defined in the DLL you are about to load? If so, you seem to already be referencing the DLL in your project settings.

You only need to work with reflection:

 Dim obj As Object = ass.CreateInstance("ICRDataLayer", True) Dim t as Type = obj.GetType() Dim method as MethodInfo = t.GetMethod("DoSomething") method.Invoke(obj, ...) 

Edit: if the application implements ICRDataLayer and the plugin simply implements the interface, you need a plugin to provide the factory for you: (sorry for the C # code, I am not familiar with the VB.NET syntax)

 // in each of plugins: static class CRDataLayerFactory // class name is a contract, { // should be the same for all plugins static ICRDataLayer Create() { return new CRDataLayerImplementation(); } } 

The application code should look like this:

 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, null) SQLDataSource = DirectCast(obj, ICRDataLayer) 
+3
source share

A few things to look for in your code

  • Debug and verify that the assembly is loaded correctly, in case it fails due to dependency checking
  • Instead of using GetType, use GetExportedType so that you have a smaller subset to iterate through
  • CreateInstance should use your loadType, not the interface (you cannot create an object from the interface)
  • Personally, I donโ€™t like to name my variable ass, I would shorten it to assembly instead: :)
+1
source share

All Articles