Can Autofac compose existing objects with Mef dependencies?

263 views Asked by At

I am integrating a mef-based ServiceLocator with Autofac. The current locator is able to compose an existing object by setting up a CompositionBatch and then injecting dependecies on the object. A simple repro:

public void MefCompositionContainer_CanComposeExistingObjects()
{
    //1. Initialize Mef
    var composablePartCatalogs = new List<ComposablePartCatalog>
    {
        new AssemblyCatalog(Assembly.GetExecutingAssembly())
        //A lot more here..
    };

    var aggregateCatalog = new AggregateCatalog(composablePartCatalogs);
    var container = new CompositionContainer(aggregateCatalog, true);
    //2. Mef is able to compose existing object
    var objectWithPropertyImport = new ClassWithPropertyImport();
    Compose(container, objectWithPropertyImport);
    objectWithPropertyImport.ImportOfMefExport.Should().NotBeNull();
}

static T Compose<T>(CompositionContainer container, T value)
{
    var batch = new CompositionBatch();
    batch.AddPart(value);
    container.Compose(batch);
    return value;
}

The following classes are required:

[Export]
public class MefExport { }

//Note that this class does not have the [Export] attribute
public class ClassWithPropertyImport
{
    [Import]
    public MefExport ImportOfMefExport { get; set; }
}

Is it possible to accomplish the same with Autofac? If so - what should be added / changed here to compose objectWithPropertyImport?

public void Autofac_CanComposeExistingObjects()
{
    //1. Initialize Mef
    var composablePartCatalogs = new List<ComposablePartCatalog>
    {
        new AssemblyCatalog(Assembly.GetExecutingAssembly())
        //A lot more here..
    };

    var aggregateCatalog = new AggregateCatalog(composablePartCatalogs);

    //2. Initialize Autofac and setup mef-integration
    var builder = new ContainerBuilder();
    builder.Register(c => new AutofacExport()).Exported(x => x.As<AutofacExport>());
    builder.RegisterComposablePartCatalog(aggregateCatalog);

    var ioc = builder.Build();

    var objectWithPropertyImport = new ClassWithPropertyImport();
    // Now what?

    // Updated according to solution from Travis Illig.
    // The following code works for me:
    ioc.InjectProperties(objectWithPropertyImport);
    objectWithPropertyImport.ImportOfMefExport.Should().NotBeNull();
}
1

There are 1 answers

0
Travis Illig On BEST ANSWER

If all you need to do is inject the properties of a new object using Autofac, then use the InjectProperties method on the lifetime scope / container.

using Autofac;

public class ClassWithPropertyImport
{
    public MyExport ImportedProperty { get; set; }
}

public class MyExport { }

var builder = new ContainerBuilder();
builder.RegisterType<MyExport>();
var container = builder.Build();

using(var scope = container.BeginLifetimeScope())
{
    var c = new ClassWithPropertyImport();
    scope.InjectProperties(c);
    c.ImportedProperty.Should().NotBeNull();
}

As long as the types you're injecting are registered with Autofac, it should work fine. You don't need the type of the thing you're injecting onto registered. (Note the ClassWithPropertyImport is not registered with Autofac but the MyExport class is.)

Keep in mind it does mean Autofac needs to resolve the MyExport type - so if it has dependencies, those do need to be registered with Autofac as well.