MEF is a great composition platform. It is great because the power and flexibility it delivers, and at the same time, the learning curve is low. When it comes to part registration, MEF out of the box supports so called attributed programming model, which allows the discoverability simply by applying Export attributes on the parts we want to make available to the world, and Import attributes on the parts which need to consume other parts. However, using this default programming model, the developer has no way of introducing any build strategies which get executed during part’s creation when a concrete part is requested. This concept, know as Chain of Responsibility design pattern, is implemented by many (if not all) dependency injection containers. Most of them allow the developer to add new actions which are executed as part of object creation. Sadly enough, there’s no such facility in MEF. This implies yet another limitation – lack of support for custom object factories. This means it is always MEF who creates parts’ instances.
Luckily, MEF is extensible. It allows to develop completely new programming models by implementing custom catalogs (like the ConventionCatalog which is a part of MefContrib). It also enables the developers to implement custom export providers, whose role it to provide exports from various sources =) In this post I am going to introduce the FactoryExportProvider which extends MEF by allowing to define object factories.
Introducing Custom Factories
When you want co take control over instance creation in MEF, you basically have two options. Either create part manually and then call ComposeExportedValue method on that part as presented on the following listing
var component = new ExternalComponent2();
container.ComposeExportedValue(component);
or use property export as presented below.
[Export]
public IExternalComponent Component1
{
get
{
return new ExternalComponent3(/* Constructor Initialization */);
}
}
The first solution, however, is not very elegant. It also registers new part as singleton. The second one is better, but still the part will be created only once, and reused across many requests. Also note that in both solutions, a problem arises when it comes to injecting target part’s constructor – we don’t have access to the container so we can’t pull required parts from it. Of course we could get a reference to the container, but doing so only for this purpose will make the code more sloppy.
Meet FactoryExportProvider
The FactoryExportProvider is an elegant solution to the outlined problems. Consider the following sample code:
var provider = new FactoryExportProvider()
.RegisterInstance<IExternalComponent>(ep => new ExternalComponent2())
.Register<IExternalComponent>("part4", ep => new ExternalComponent4(
ep.GetExportedValue<IExternalComponent>(),
ep.GetExportedValue<IMefComponent>()));
var container = new CompositionContainer(anyCatalog, provider);
provider.SourceProvider = container;
You can clearly see two parts being registered, both with the same interface. The first one is registered as a singleton (shared in MEF), but more interestingly, the second is registered as transient (non shared in MEF) and will be created each time the part is requested. As part of the registration process, a factory method should be passed (this is not required, read on to find out why) which is responsible for delivering instances. Note also an elegant, though widely adapted, solution to resolving complex constructors. In the example, the ExternalComponent4 has a dependency on IExternalComponent and IMefComponent parts. However, thanks to the fact that the resolution method has access to the source provider (ExportProvider instance), we can use it to satisfy additional imports. Just remember to set SourceProvider property of the FactoryExportProvider to something meaningful (at least to the FactoryExportProvider instance itself as the SourceProvider is null by default). More common is to set it to the CompositionContainer instance.
FactoryExportProvider is quite flexible. It allows to register a fallback factory method which gets executed whenever part is registered without supplying the factory method enabling to design single resolution method for a subset or all parts registered in the factory. See the following example.
private static object FactoryMethod1(Type type, string registrationName)
{
if (type == typeof(IExternalComponent) && registrationName == null)
return new ExternalComponent1();
if (type == typeof(IExternalComponent) && registrationName == "external2")
return new ExternalComponent2();
return null;
}
var provider = new FactoryExportProvider(FactoryMethod1);
var container = new CompositionContainer(someCatalog, provider);
// Registration
provider.Register(typeof(IExternalComponent));
provider.Register(typeof(IExternalComponent), "external2");
The code presented in this post is available as part of MefContrib Project. Latest version is available on my fork. In the coming days I will push it to the main repo though! This export provider is also used by IoC plumbing infrastructure, which is also part of MefContrib Project, which enables integration of IoC and MEF. I blogged about particular implementations for Unity container here and here.
Hope you like it!
1 comment:
Hi Piotr,
I have a requirement to add Export some of the 3rd party types with my own custom metadata attribute using MEF. I had gone through ConventionCatalog & FactoryExportProvider samples on your blog. But when I tried in my proto app I am not getting any Lazy instance of newly add export. Actually what I am looking for is to
[ImportMany(AllowRecomposition = true)]
public IEnumerable MyProperty { get; set; }
here IExternalComponent I have to export with metadata IEnvironmentMetadataAttribute.
Can you suggest any alternate.
Post a Comment