2

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.

Dan Bryant
  • 27,329
  • 4
  • 56
  • 102
  • 1
    MEF is not an IOC container. http://blogs.msdn.com/sburke/archive/2008/10/03/mef-n-ioc.aspx – Cameron MacFarland Mar 13 '10 at 15:42
  • Also http://stackoverflow.com/questions/293051/is-mef-a-dependency-injection-framework Consider using StructureMap, Ninject, CastleWindsor or Autofac instead. – Cameron MacFarland Mar 13 '10 at 15:44
  • Thanks for the links; they were quite helpful. I've updated the title of my question to better clarify what I'm after. MEF does seem like a good fit for my requirements, since extensibility is the main thing I'm after. I don't yet have a good understand of IoC; do you think it's better suited for the cases I've mentioned? – Dan Bryant Mar 13 '10 at 16:29
  • 1
    MEF is an extension framework, so it's good for bolting on extensions after the fact. Since IOC is a little bit simpler I'd recommend starting with that. 1. I'm not sure any IOC can restrict access to a service the way you describe. 2. IOCs have more control over how an object is instantiated. You can pass parameters in each time an object is requested to get different versions. I'm not sure if MEF handles this, as I think MEF just loads extensions once. – Cameron MacFarland Mar 13 '10 at 16:42
  • To be perfectly honest, I do find MEF a little bit freaky. I sprinkle a few attributes, call Compose and suddenly this whole object hierarchy springs into existence with magically appearing references. It makes me feel like Jack with a handful of magic beans. Definitely a lot to explore still. – Dan Bryant Mar 13 '10 at 17:12
  • @Cameron: the blog post basically says *You can use it kind of like one, but that's not what it's really meant for.* Not really a convincing argument. I use MEF as an IoC container and don't see a problem with that. – Wim Coenen Mar 14 '10 at 00:06
  • @Wim Thats like saying you use your car to drive to your kitchen. Sure your car can transport you there, but it can also do so much more. – Cameron MacFarland Mar 14 '10 at 01:27

1 Answers1

1

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
  • 66,094
  • 13
  • 157
  • 251