DI (Autofac) in a plugin architecture: Is one separate DI container per plug-in OK?

倾然丶 夕夏残阳落幕 提交于 2020-01-14 07:51:33

问题


I am trying to introduce DI (with Autofac) into an existing Windows Forms application.

This application has a basic plug-in architecture where each plugin displays its own form. On startup, the application scans registered assemblies for types that implement IPlugin, and then activates these using Activator.CreateInstance:

public interface IPlugin
{
    Form MainForm { get; }
}

I cannot change this given framework. This means, each plugin class is instantiated through non-DI means, and it seems to me that I will therefore have to bootstrap a separate DI container for each plugin.

My question is, is creating a separate ContainerBuilder and container per plugin OK and still reasonably efficient? (There will be approx. 10 different plugins.) Or should there only be one DI container for the whole application?

I've provided some sample code of my current solution below.


using Autofac;
using System.Windows.Forms;

public class Plugin : IPlugin  // instantiated by Activator
{
    public Form MainForm { get; private set; }

    public Plugin()  // parameter-less constructor required by plugin framework
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule(new Configuration());
        var container = builder.Build();

        MainForm = container.Resolve<MainForm>();
        // ^ preferred to new MainForm(...) because this way, I can take
        //   advantage of having dependencies auto-wired by the container.
    }
}

internal class Configuration : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<MainForm>().SingleInstance();
        // ... more plugin-specific registrations go here...
    }
}

internal class MainForm : Form { /* ... */ }

I'm also not sure whether creating a container in the plugin constructor and then simply forgetting about it, but leaving it to do auto-wiring in the background, is OK?


回答1:


You container usage should ideally follow the Register Resolve Release pattern (RRR). I know that you said that you can't change the current Activator.CreateInstance usage, but it can still be helpful to understand how it really ought to be.

If you didn't have that constraint, there should only be a single container instance, hosted by the parent application itself. This could then be used to compose all the plugins. This would enable the plugins to share dependencies. This is the route taken by MEF, which also addresses extensibility scenarios.

Now, since you can't do that, the next-best thing you can do is to have a container per plugin as you suggest. It mostly becomes an implementation detail at that point. In each plugin, you should still follow the RRR pattern.

Would it be inefficient? Unless you have a lot of plugins and create and destroy them all the time, a couple of different containers shouldn't matter much. However, it's better to measure than to create premature optimizations.

In this scenario, you can only share a container by making it static. However, this makes things more complicated than they need to be, so don't go that route unless absolutely necessary.




回答2:


I'm also not sure whether creating a container in the plugin constructor and then simply forgetting about it, but leaving it to do auto-wiring in the background, is OK?

Looking at my own question many months later, I dare say that just forgetting the container is not OK, since (a) it is IDisposable and should be treated as such, and (b) some components' lifetimes are bound to the container's, thus the container's lifetime should be explicitly ended; be it in the form's Dispose method or when its FormClosed event is triggered.



来源:https://stackoverflow.com/questions/3940675/di-autofac-in-a-plugin-architecture-is-one-separate-di-container-per-plug-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!