I have set up an assembly catalog:
private CompositionContainer GetContainer() {
// initialize directory info
ExtensionDirectory = new DirectoryInfo(
I think these concerns are already separated: discovery is handled by catalogs, and composition is done by export providers.
In the typical case, you just pass a catalog directly to the container and for convenience it will automatically take care of creating an CatalogExportProvider for it.
But you can also create one or more export providers yourself and pass them to the container with this constructor overload. (You may also have to set the SourceProvider to point back at the container after that, so that the export providers can use each other.)
You can create your own ExportProvider implementations, and they don't even have to be backed by catalogs.
In order to satisfy the requirements, I created 3 classes:
public sealed class CompositionFactory {
[Import("Provider")]
private IProvider importProvider;
/* MEF initialization */
}
[Export("Provider")]
public sealed class AssemblyProvider : IProvider {
private CatalogExportProvider _provider;
}
internal sealed class ComposableAggregate { }
The CompositionFactory
initializes MEF to discover the AssemblyProvider
. When the provider initializes:
private CatalogExportProvider InitializeProvider() {
// directory catalog
var dirCatalog = new DirectoryCatalog(ExtensionDirectory.FullName);
return new CatalogExportProvider(dirCatalog);
}
...we return a CatalogExportProvider. I can now use an API to the CompositionFactory:
public ISomething GetSomething(string ContractName, object ContractParam) {
// implementation
}
...to query for the correct composable part using a contract name:
public ComposablePartDefinition GetPartDefinition(string ContractName) {
return _provider.Catalog.Parts
.Where(p => p.ExportDefinitions
.Select(e => e.ContractName)
.Any(c => c == ContractName))
.FirstOrDefault();
}
The work is then completed in the ComposableAggregate helper class:
internal ISomething Value {
get {
return _container.GetExport<IEntity>(_contractName).Value;
}
}
private CompositionBatch CreateBatch() {
CompositionBatch batch = new CompositionBatch();
// create composable part from definition
ComposablePart importDef = CreatePart(_contractName);
batch.AddPart(importDef);
return batch;
}
private ComposablePart CreatePart(string ContractName) {
// get part definition from catalog
return _provider.GetPartDefinition(ContractName).CreatePart();
}