Autofac and MEF integration

By Mirek on (tags: Autofac, MEF, Plugins, categories: architecture)

A time ago I have presented a way of implementing wpf plugins with use of Managed Extensibility Framework. Today I will show you how to integrate your MEF exports with Autofac dependency container.

For that we will need of course MEF which is stored in System.ComponentModel.Composition assembly, Autofac and Autofac.MEF packages. Having that in place we can manage our MEF exports with use of autofac container as it would be regular components registered by autofac builder. More on that you can read on autofac documentation, but lets see how it works on a simple example.

Let’s assume we have such a simple plugin interface

public interface IFoo
{
    int Distance(int a, int b);
}
And for the sake of simplicity we are exporting class defined in the same library
[Export(typeof(IFoo))]
public class Foo : IFoo
{
    public int Distance(int a, int b)
    {
        return Math.Abs(a - b);
    }
}

Now in the client code all we need is to have this

   1: var builder = new ContainerBuilder();
   2: var catalog = new AssemblyCatalog(typeof(Program).Assembly);
   3: builder.RegisterComposablePartCatalog(catalog);            
   4: var IoC = builder.Build();

 
In line 2 we create a composable catalog in the same way as when we use MEF composition. Then we need to call RegisterComposablePartCatalog method so the autofac builder will discover all MEF exports in provided catalog. Now we can simply retrieve the instance of Foo by resolving it from the container.

   1: var foo = ioc.Resolve<IFoo>();

What about the instantiation? Well, by default all MEF exports are defined as singleton so no matter how many time you request the component you always get the same one instance. This also applies when we resolve mef exports with autofac. To change that we need to set the part creation policy on exported types to NonShared

[Export(typeof(IFoo))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class Foo : IFoo
{
    public int Distance(int a, int b)
    {
        return Math.Abs(a - b);
    }
}

This is equivalent to InstancePerDependency registration from autofac

builder.RegisterType<Foo>().As<IFoo>().InstancePerDependency();

Another nice integration feature is that with MEF we can export many components that implements one interface. This is especially useful when we implement plugins. We have one common interface that we want every plugin implements in order to provide added functionality. Then with use of MEF we can simply have a collection of plugins composed on a property of some enumerable type as shown below

[ImportMany(typeof(IFoo))]
private IEnumerable<Lazy<IFoo>> Plugins { get; set; }

With use of autofac container this is even simpler. We resolve it like this

var foos = ioc.Resolve<IEnumerable<IFoo>>();

to get immediate instances, or like this

var foos = ioc.Resolve<IList<Lazy<IFoo>>>();

to get lazy loaded instances. That is handy, isn’t it?

One thing that we should know is that the autofac component registrations are not automatically registered and available for types exported with MEF. That means that by default you cannot use components registered in autofac and resolve them inside your exported MEF type. I guess the main reason for this is a security, so your internal components are not available for the external assembly for instance. However we can change that by providing an explicit export of components that we want to have imported in mef components. Let say our Foo class requires some Boo object which is registered with autofac and must be resolved during instantiation of Foo.

   1: [Export(typeof(IFoo))]
   2: [PartCreationPolicy(CreationPolicy.NonShared)]
   3: public class Foo : IFoo
   4: {
   5:     public Boo Boo { get; set; }
   6:  
   7:     public int Distance(int a, int b)
   8:     {
   9:         return Math.Abs(a - b);
  10:     }
  11:  
  12:     [ImportingConstructor]
  13:     public Foo(Boo boo)
  14:     {
  15:         Boo = boo;
  16:     }
  17: }

In line number 12 we decorate the non default importing constructor which should be used to resolve component, same way as we would define it for MEF composition. To have that working we need to register type Boo as exported component in autofac like this

builder.RegisterType<Boo>().Exported(x => x.As<Boo>());

That’s it. We have now one container for all internal and external components and one way to resolve them. Additionally we can now benefit from all lifetime management features that are part of autofac.