A Mef CompositionContainer
is unable to resolve Autofac dependencies when used according to documentation at http://docs.autofac.org/en/latest/integration/mef.html.
I have a large code-base that has extensive use of a ServiceLocator and singletons... The service-locator does all object-creation, composition etc by using a cached System.ComponentModel.Composition.Hosting.CompositionContainer
. (Also, note that we currently use/need metadata support) I am attempting to switch from this to a more modern architecture. For this to work, the existing Mef-based (‘CompositionContainer’-based) service-locator will have to cooperate with the Autofac IoC container.
The following function
- Creates a Mef
CompositionContainer
- Demonstrates that MEF is able to resolve a simple export
- Configures Autofac to register with MEF and export the
AutofacExport
to MEF by using the.Exported
extension method. - Demonstrates that Autofac can resolve a mef-component with a dependency definend in Autofac
- Demonstrates that Mef is unable to resolve the exported component component with the Autofac dependency.
The exception thrown is: ImportCardinalityMismatchException("No exports were found that match the constraint: ContractName MefExportWithDependency RequiredTypeIdentity MefExportWithDependency"
is thrown.
public void MefResolve_ObjectWithDependency_CanResolveWhenAutofacRegistersDependeyncy2()
{
//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. As expected this is resolved
container.GetExport<MefExport>().Should().NotBeNull();
//3. Initialize Autofac
var builder = new ContainerBuilder();
builder.Register(c => new AutofacExport()).Exported(x => x.As<AutofacExport>());
builder.RegisterComposablePartCatalog(aggregateCatalog);
var ioc = builder.Build();
//4. Here Autofac is correctly providing the dependency to the mef ImportingConstructor
ioc.Resolve<MefExportWithDependency>().AutofacExport.Should().NotBeNull();
//5. The next line will throw ImportCardinalityMismatchException
container.GetExport<MefExportWithDependency>();
}
There code above expects the following classes to be defined:
public class AutofacExport { }
[Export]
public class MefExport { }
[Export]
public class MefExportWithDependency
{
public AutofacExport AutofacExport { get; set; }
[ImportingConstructor]
public MefExportWithDependency(AutofacExport autofacExport)
{
AutofacExport = autofacExport;
}
}
Note: I have also had a look at https://www.nuget.org/packages/MefContrib.Integration.Autofac/ - which promises to integrate Mef with Autofac. However, I am not able to find relevant documentation on how to configure that, and the package does not have a lot of usage.
I think you may have misunderstood the way the Autofac.Mef package is supposed to work. While it brings MEF items into Autofac, letting Autofac understand the export/import attributes and items registered in the MEF catalogs, it's a one-way operation - it doesn't push Autofac registrations into MEF or allow a MEF
CompositionContainer
to use Autofac.I believe what you want is the MefContrib.Integration.Autofac package you mentioned, which appears to allow things to flow the other direction - from Autofac into MEF.
A good place to see how it works is in their repository, where they have some unit tests showing integration where MEF is resolving Autofac items. Here's one such test:
As you can see, they have an adapter for Autofac containers that sort of "converts" them into something MEF can understand. They also have some unit tests showing bi-directional integration - MEF resolving from Autofac, Autofac resolving from MEF.
I've never personally used that package, but I think if you check out the tests and how they've got those set up it should get you on your way.