What is the best way to design an MEF-based plugin architecture that has dependencies between plugins? For example:
class MainForm
{
CompositionContainer container;
[ImportMany]
IEnumerable<Lazy<IWindow>> windows;
public MainForm()
{
this.container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
this.container.ComposeParts(this);
}
public void DoSomething()
{
foreach (var winPart in windows)
{
Debug.WriteLine(winPart.Value.Name);
}
}
}
interface IWindow
{
string Name { get; }
}
delegate void AnEvent(object sender, EventArgs e);
interface IEventManager
{
event AnEvent AnEvent;
void OnAnEvent(object sender, EventArgs eventArgs);
}
[Export(typeof(IEventManager))]
class EventManager : IEventManager
{
public event AnEvent AnEvent = delegate { };
public void OnAnEvent(object sender, EventArgs eventArgs) { AnEvent(sender, eventArgs); }
}
[Export(typeof(IWindow))]
class Window1 : IWindow
{
[Import]
IEventManager eventMgr;
public Window1() { }
public string Name
{
get
{
eventMgr.OnAnEvent(this, new EventArgs());
return "Window1";
}
}
}
[Export(typeof(IWindow))]
class Window2 : IWindow
{
[Import]
IEventManager eventMgr;
public Window2() { this.eventMgr.AnEvent += eventMgr_AnEvent; }
void eventMgr_AnEvent(object sender, EventArgs e)
{
Debug.WriteLine("Event from Window 2");
}
public string Name { get { return "Window2"; } }
}
In the Window2
constructor this.eventMgr
is null. I would expect it to be composed by MainForm. One approach is to have multiple CompositionContainers
but if you do that there are two instances of EventManager
rather than one shared instance. What would be the best way of doing this?
In exploring this question more, inter-dependencies are perfectly allowed. The key is to have the assemblies available in the catalog passed to the CompositionContainer that is being used to compose the parts. Then the following code helped in allowing one plugin to access another plugin: