Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to inject an existing instance into a MEF plugin?

Tags:

c#

.net-4.0

mef

We are creating an application which supports plugins using MEF. We are determining what type of plugins the user is able to create, and want to use dependency injection to provide this type of plugin with the data it needs.

For example, we make a plugin that is able to display a list. To achieve this, it needs the existing instance of the IRepository for the type of data the list will display.

The IRepository is created somewhere else in a datacontext class, so we are unable to let MEF itself create an instance of the IRepository.

My idea is to inject the existing instance of the IRepository into the plugin via the importingconstructor, however for this to work I need to make the already instantiated IRepository known to MEF, and I haven't been able to figure out how to do it. Any help would be appreciated.

like image 379
Jesse van Assen Avatar asked Feb 22 '23 18:02

Jesse van Assen


1 Answers

The easiest way is to compose an existing value in the container, e.g.:

var repo = // Create repo
container.ComposeExportedValue<IRepository>(repo);

But this will only allow 1 instance of the IRepository to exist, because it doesn't give you direct control over the ComposablePart that is created. If you want more fine grained control, you can use a CompositionBatch to great effect:

var batch = new CompositionBatch();
var repo = // Create repo

var repoPart = batch.AddExportedValue<IRepository>(repo);
container.Compose(batch);

// repo will now be injected on any matching [Import] or [ImportingConstructor]

And later on:

var batch2 = new CompositionBatch(null, new[] { repoPart });
var repo2 = // Get new repo

var repo2Part = batch2.AddExportedValue<IRepository>(repo2);
container.Compose(batch2);

Because I have access to the ComposablePart instance provided by the batch, I can remove it later on. There are other ways of importing attribute-less parts, generally through property exports:

[Export(typeof(IRepository))]
public IRepository Repository
{
    get { return CreateRepository(); }
}

But that of course would require you to be able to create an instance of your repository at composition time, which may or may not be possible.

Lastly, there is the option to use an alternative programming model. The default (and most common) in MEF is the attributed programming model, whereby you utilise [Export] and [Import] attributes to control your composition, but in MEFContrib (and forthcoming in MEF2) is the ability to use a registration programming model whereby parts are composed based on a mechanism similar to most other IoC containers.

like image 190
Matthew Abbott Avatar answered Apr 27 '23 21:04

Matthew Abbott