0

The problem

I'm working on a project with a plugin like system. The project structure is defined as follows:

- Solution
    - Project A (Cli)
    - Project B (Core logic)
    - Project C (Plugin)

Project A is the startup project, Project B contains the core logic and Project C is a plugin, which implements an interface in project B. Project A only has a reference to Project B and Project C only has a reference to Project B.

To visualize:
visualization

Since I do not reference Project C from Project B (and do not instantiate the class directly), code like AppDomain.CurrentDomain.GetAssemblies() (inside Project B) does not return Project C.

However, once I do (from Project B): var MyImplementation = new MyImplementation(), AppDomain.CurrentDomain.GetAssemblies() does return the assembly, since it's known and loaded at runtime as I instantiated the class MyImplementation explicitly from code.

The question

From Project B, I want to get all assemblies which implement a specific interface from Project B and instantiate them.

So, how do I get these (seemingly) unknown assemblies to get loaded at runtime?

Devator
  • 3,686
  • 4
  • 33
  • 52
  • https://stackoverflow.com/questions/26733/getting-all-types-that-implement-an-interface is this helping? – Louis Go Feb 17 '20 at 09:30
  • @LouisGo unfortunately, `AppDomain.CurrentDomain.GetAssemblies()` does not contain the assembly. – Devator Feb 17 '20 at 09:59

1 Answers1

1

I don't think it's possible to know if an assembly contains a class that implement your interface without loading it.

What you can do is provide a directory where you put all your plugins assemblies.

So you can load your plugins in your AppDomain like this :

public static Assembly[] MyPlugins { get; private set; }

public static void LoadAssemblies()
{
   MyPlugins = Directory.GetFiles(lookingDirectory, "*.dll")
                .Select(assemblyPath =>
                {
                    AssemblyName an = AssemblyName.GetAssemblyName(assemblyPath);
                    return Assembly.Load(an);
                })
                .ToArray();
}

And then you can find all types that implements your interface like this :

MyPlugins.SelectMany(assembly => assembly.GetTypes())
    .Where(type => typeof(IYourInterface).IsAssignableFrom(type))
    .Select(type => (IYourInterface)Activator.CreateInstance(type))

And then you can iterate on each implementation of your interface to call a shared method for example.

Devator
  • 3,686
  • 4
  • 33
  • 52
Coding Seb
  • 83
  • 1
  • 5
  • Yes, I thought about having a `plugin` folder and putting DLL's into it. If that's the only way, then I might do that. – Devator Feb 17 '20 at 10:00
  • Yes you need a way to identify which assembly contains your plugins. – Coding Seb Feb 17 '20 at 10:03
  • You could also name your plugins with a suffix or prefix and filter all dlls that are in your root folder and are named this way – Coding Seb Feb 17 '20 at 10:04
  • Or you can also provide a command in your cli like `loadplugin "Path/ToMyPlugin"` and save this path in config file. In each loading of your program you can read your file and reload all given assemblies – Coding Seb Feb 17 '20 at 10:10