views:

148

answers:

1

I've begun experimenting with dependency injection (in particular, MEF) for one of my projects, which has a number of different extensibility points. I'm starting to get a feel for what I can do with MEF, but I'd like to hear from others who have more experience with the technology. A few specific cases:

  1. My main use case at the moment is exposing various singleton-like services that my extensions make use of. My Framework assembly exposes service interfaces and my Engine assembly contains concrete implementations. This works well, but I may not want to allow all of my extensions to have access to all of my services. Is there a good way within MEF to limit which particular imports I allow a newly instantiated extension to resolve?

  2. This particular application has extension objects that I repeatedly instantiate. I can import multiple types of Controllers and Machines, which are instantiated in different combinations for a Project. I couldn't find a good way to do this with MEF, so I'm doing my own type discovery and instantiation. Is there a good way to do this within MEF or other DI frameworks?

I welcome input on any other things to watch out for or surprising capabilities you've discovered that have changed the way you architect.

+1  A: 

Is there a good way within MEF to limit which particular imports I allow a newly instantiated extension to resolve?

Load the extension code in a separate container, and make sure that the restricted parts are not available in that container. Let's simplify the situation to these classes to construct an example:

[Export]
public class MyExtension
{
   [Import]
   public PublicService Service { get; set; }

}

[Export]
public class PublicService
{
}

[Export]
public class InternalService
{
}

[Export]
public class Program
{
   [Import]
   public MyExtension Extension { get; set; }

   [Import]
   public PublicService Service1 { get; set; }

   [Import]
   public InternalService Service2 { get; set; }
}

The goal is to allow MyExtension to import PublicService, but not InternalService. Internal code like Program should be able to import anything. You can achieve that like this:

var publicCatalog = new TypeCatalog(typeof(PublicService), typeof(MyExtension));
var publicContainer = new CompositionContainer(publicCatalog);

var internalCatalog = new TypeCatalog(typeof(Program), typeof(InternalService));
var internalContainer = 
    new CompositionContainer(internalCatalog, publicContainer);

var program = internalContainer.GetExport<Program>();

This code will not throw a composition exception. If you now change the import on MyExtension to the forbidden InternalService, you will get a composition exception as desired.

A side effect of this set-up is that PublicService cannot import any private services either, just like MyExtension. This kind of makes sense, because otherwise nothing would stop PublicService from exposing a private service via a property.

I have used TypeCatalog for the example, but in practice you should probably use something like the FilteredCatalog sample.

This particular application has extension objects that I repeatedly instantiate. I can import multiple types of Controllers and Machines, which are instantiated in different combinations for a Project. I couldn't find a good way to do this with MEF, so I'm doing my own type discovery and instantiation. Is there a good way to do this within MEF or other DI frameworks?

You might just be after the PartCreationPolicy attribute, which controls whether a part is shared (as in, created only once per container) or instantiated multiple times for each import. You can also specify the RequiredCreationPolicy parameter in an import attribute.

If that doesn't solve your problem, take a look at the PartCreator sample in the MEF sources (though note that it will probably soon be renamed to ExportFactory, it already has been in the silverlight edition of MEF).

Wim Coenen
Thanks, that's very helpful. I'll have to do some more reading on Catalogs.
Dan Bryant