I'm building a WPF (desktop) application, utilizing dependency injection, a DI container and the Register-Resolve-Release pattern. My application also loads plugins from separate assemblies during startup, and the plugins are registered with the DI-container. I resolve my entire object graph once in the composition root at startup, however, I'm having some issues with resolving my plugins, and I'm wondering whether it is OK to inject the DI container into a factory to resolve unknown types?.
My plugins all:
- implement a common interface,
IPlugin
- need to be transient (since multiple instances can live simultaneously)
- are dependent on runtime values to configure them when they are being initialized
- might, or might not, have other dependencies injected through their constructor
I have started to implement a PluginFactory
to initialize the plugins when I need them, since, as Mark Seemann says: "Any place where you need a run-time value to construct a particular dependency, Abstract Factory is the solution."
However, I cannot just new()
the plugins in my factory, since I don't know their types and dependencies.
I have thought of several solutions:
I can inject the DI container into the constructor of the
PluginFactory
, resolve the plugins at runtime and call it a day. However, that goes against the RRR-pattern.I can inject
IEnumerable<IPlugin> plugins
through the constructor of thePluginFactory
. However, this would violate the transient requirement, since I would only have one copy of each instance[*Wrong]. I can solve this by implementingICloneable
on all my plugins and clone them in the factory, however, this is both hard to do correct with dependencies and clutters all the plugins.
[*Wrong] Edit: Note, according to the selected answer, this is wrong! Therefore, option #2 is the best option, as long as you register the lifetime of the plugins to be transient.
I can inject the plugin types rather than instances into the
PluginFactory
and use theActivator.CreateInstance<T>()
to create the instances. I could even define a common constructor signature for the plugins and pass parameters to the Activator to initialize them with dependencies. However, this violates my requirement that the plugins have different dependencies, and it also leads to the constrained construction anti-pattern.Finally, building on 3. I can inject plugin types and use reflection to sort out the dependencies of the plugins. However, this sounds like it is a lot of work and makes me wonder whether I'm trying to build or copy the resolve methodology from DI containers. The latter is something I definitely don't want to do or see the point with.
So, out of my alternatives in prefer #1, even though that goes against the RRR pattern.
What would be the best way to instantiate my plugins (I'm leaning towards #1). Have I missed some alternatives entirely? Or have I perhaps misjudged some of my other alternatives?