Using MEF as an IoC container
The Managed Extensibility Framework is a new wonderful addition to .NET 4 and Silverlight 4. The main purpose of MEF is to handle the extensibility and plug-in capability of an application. It features a very simple and elegant method for creating objects and resolving dependencies by decorating your code with import and export attributes.
Managing and resolving dependencies and creating objects is pretty much what a simple IoC (Inversion of Control) container does. So, can we use MEF for this?
The MEF man Glenn Block once said that ”you should use MEF to manage your unknown dependencies and an IoC container to manage your known dependencies.” However, I have found that MEF can work pretty well as your one stop solution for all dependencies. It is especially nice if you are building a Silverlight application that already uses MEF (for example to download XAPs dynamically). Why include a separate third party IoC container when there is one built in already?
Here is a short guide for those who want to use MEF for dependency injection in Silverlight.
MEF libraries
First of all, you need to add a reference to the MEF libraries. They are included with Silverlight 4:
System.ComponentModel.Composition – You need this reference anywhere you use the basics of MEF such as importing and exporting.
System.ComponentModel.Composition.Initialization – You need this reference where you actually initialize and configure the container.
ServiceLocator class
To use MEF for resolving dependencies I have built a simple class to set things up and provide a way to create or retrieve instances. This is the code for a simple version of this class:
public static class ServiceLocator
{
private static CompositionContainer _container;
private static AggregateCatalog _catalog;
public static void Initialize()
{
_catalog = new AggregateCatalog(new DeploymentCatalog());
_container = CompositionHost.Initialize(_catalog);
}
public static T GetInstance<T>()
{
return _container.GetExportedValue<T>();
}
}
The Initialize() method sets up an AggregateCatalog and feeds it with a DeploymentCatalog. The AggregateCatalog can contain many MEF catalogs that are added at runtime. Using an AggregateCatalog is not absolutely necessary in this simple example but it is a preparation for loading dependencies dynamically in the future.
The DeploymentCatalog is used in Silverlight for working with XAP files. It is a very handy class for loading external XAPs if your application is split up in modules. Creating a DeploymentCatalog without any parameters will create a catalog for the main application XAP file and this will allow us to access the exported types in all the assemblies of our main XAP file.
When we call CompositionHost.Initialize() our assemblies will be scanned by MEF and all exports are discovered. We are then ready to call the GetInstance<T>() method whenever we need an instance of an exported class.
Exporting types
Traditional IoC containers often involve configuring components using either XML or registering them using code. With MEF you simply put an [Export] attribute on your class to indicate that it should be available for composition:
[Export]
public class Car
{
...
}
This will expose the type Car to MEF and lets you retrieve it in IoC fashion like this:
var car = ServiceLocator.GetInstance<Car>();
Often you want to expose a certain interface that your type implements. You can do this by supplying the type in the [Export] attribute like this:
[Export(typeof(ICar)]
public class Car : ICar
{
...
}
The default behavior in MEF is to treat exports as singletons. That is, if you don’t specify anything to override this behavior you will only get one instance of the Car object in your application no matter how many times you call GetInstance<Car>(). Actually, if the exported type does not specify anything the default is to allow either singleton or non shared so it is up to the caller to decide what he wants.
If you want unique instances to be created every time you retrieve an instance of your type you can specify this using an extra attribute on your class:
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class Car
{
...
}
Dependency injection
Of course an application is seldom built with only a single class. Most likely you have many parts that fit together and you want to use the IoC container to resolve everything smoothly for you using dependency injection. MEF can do this as well, but you have to decorate the constructor to use with the [ImportingConstructor] attribute:
[Export]
public class Car
{
[ImportingConstructor]
public Car(Engine engine)
{
}
}
[Export]
public class Engine
{
}
When retrieving a Car instance MEF will automatically create and inject the Engine in the constructor of the class just like an ordinary IoC container would.
All in all, those 20 lines of code is all you need to get started with MEF as an IoC container. You can now retrieve instances of your objects with injected dependencies and that’s pretty much what you need in most cases.
Conclusion
I wanted to keep this example as simple as possible and have deliberately left out topics like object lifetime, dynamically loading XAPs and so on. I am planning to write about those things in upcoming posts.
I think MEF provides a great alternative to the traditional IoC containers. It is very easy to setup and get started with. I also like the fact that all configuration sticks with the class, which makes it easy for newcomers in your project to pick things up quickly and write new components simply by looking at an existing class.
I believe MEF is going to be central in all .NET 4 development. Don’t miss out!
Recent Comments