Let’s talk about MEF – Part 1

Hello and welcome :),

This series is retired due to me spending most of my time on the .net core side. Thanks to feedback, this series might be revived at one point under .net core since I recently found out that there is a port for MEF on .net core but at this point I don’t have full knowledge of the changes.

So we talked about what Dependency Inversion and Injections are (see here), and last time we looked at how we can make our own IoC container.

I also promised we will start having a look at the mature IoC containers and how they work, so the first one will be the Managed Extensibility Framework (MEF).

I do admit that I am a little biased towards this framework due to a number of reasons and I hope you will understand why once we get into discussing it. Also please note that the sheer amount of information on MEF will turn this into a mini-series only about how to work with it. Otherwise, for this first post, we will have a look at the basics so that we have a basis to compare it against other frameworks.

What is MEF?

MEF is short for Managed Extensibility Framework and it’s been part of the .Net framework since version 4, which for me means quite a bit because besides making it readily available without introducing a lot of 3rd party frameworks (not that there is something inherently wrong with them), it also means that it’s used behind the scenes. I don’t know if you happen to notice but in newer versions of visual studio (I think starting with 2013), when adding plugging visual studio will actually show a progress bar when loading that mentions that the plugins are loaded (and presumably created) with MEF.

One thing to note, doing some research online, MEF is not really in the IoC category of frameworks since it’s real purpose is intended for making applications extendable through plugins. That being said, I still use it as such, and when an application matures, I might even use it for its actual purpose.

So for us to better understand MEF which has a different terminology than other frameworks I encountered, we’re going to make a project based on a metaphor so that it will be easier to follow along both with the reason and the terminology.

Starting a project with MEF

Writing the blueprints

Let’s say you own a car factory that can create any car you wish, but there’s a catch, for your factory to work, it needs to have a blueprint of what you want it to create. So let’s write that first:

namespace BlogPlayground
{
internal class Car
{

}
}

I know, anti-climactic, but let’s start small and expand. Our car, like any other, will need a few essential parts, like for example wheels, so let’s make that a requirement:

namespace BlogPlayground
{
internal class Car
{
private const int WheelCount = 4;

internal Car(WheelType wheelTypeType)
{
WheelType = wheelTypeType;
}

internal WheelType WheelType { get; }
}
}

We’re going to assume that we’re using the same type of wheel for all 4 of them, we will create an additional class for that as well:

namespace BlogPlayground
{
internal class WheelType
{
}
}

On the technical side, the reason this is a class and not an enum (in case some people were asking that), is because we might want to add additional features to the wheels and also it plays nicely into our example :).

So now we would have everything we need to make our factory working at the very basic level. But first, we will write it without MEF and then update it.

Building the factory

Here’s how it would look without MEF:

namespace BlogPlayground
{
internal class Factory
{
internal Factory()
{

}

internal Car CreateCar()
{
return new Car(new WheelType());
}
}
}

Now that we written our factory, how about testing it out so we know we’re on the right track. As always, we will be using NUnit for this task:

namespace BlogPlayground
{
using NUnit.Framework;

[TestFixture]
public class FactoryTests
{
[Test]
public void CarShouldHaveWheels()
{
Factory sut = new Factory();

Car car = sut.CreateCar();

Assert.That(car, Is.Not.Null, "car instance was not returned from the factory");
Assert.That(car.WheelType, Is.Not.Null, "car instance should have an instance of wheel types");
}
}
}

We write the test, we make sure it passes and then we can continue without worrying about making mistakes.

Notice that the creation of a car and of its wheel type are hardcoded, that wouldn’t help us build any kind of car right? So the first order of business is making our container.

For MEF to work we need to add a reference to the System.ComponentModel.Composition assembly, this can be found by adding a new reference and looking in the Assemblies section.

namespace BlogPlayground
{
using System.ComponentModel.Composition.Hosting;
using System.Reflection;

internal class Factory
{
private readonly CompositionContainer _container;

internal Factory()
{
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
_container = new CompositionContainer(catalog);
}

internal Car CreateCar()
{
return _container.GetExportedValue<Car>();
}
}
}

Now let’s look at what we have done here:

  • MEF lives inside the System.ComponentModel.Composition.Hosting namespace, that’s why we added it on line 3.

  • MEF works on the concept of “catalogs”, basically a catalog tells MEF where to look for the blueprints and pieces it needs. The AssemblyCatalog we create on line 12 tells MEF to inspect all the types in the local assembly (of course we could have provided another assembly if we wished, more on that later on).

  • On line 13 we created a CompositionContainer that received a catalog as it’s argument, this is the brains of the factory and we will see how it works on the next point.

  • On line 18 we tell the container that we want to return an object of type Car, this will make the container look through its catalog and find a blueprint for that type and the parts for it and will create a car for us.

Though if we were to run our test right now, we would get following error:

No exports were found that match the constraint: \
ContractName BlogPlayground.Car\
RequiredTypeIdentity BlogPlayground.Car

Well, at least we now confirmed that the container is doing its job and tried to look up an object of type BlogPlayground.Car. We will need to help it out in finding that contract. (blueprint in our analogy)

namespace BlogPlayground
{
using System.ComponentModel.Composition;

[Export]
internal class Car
{
private const int WheelCount = 4;

internal Car(WheelType wheelTypeType)
{
WheelType = wheelTypeType;
}

internal WheelType WheelType { get; }
}
}

So now we added the using statement for MEF and also added an attribute called [Export] on line 5 that will tell MEF that this object is exposed in the catalog for creation.

Now if we were to run our test we would get the following error:

System.ComponentModel.Composition.CompositionException : The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.

1) Cannot create an instance of type ‘BlogPlayground.Car’ because a constructor could not be selected for construction. Ensure that the type either has a default constructor, or a single constructor marked with the ‘System.ComponentModel.Composition.ImportingConstructorAttribute’.

Resulting in: Cannot activate part ‘BlogPlayground.Car’.\
Element: BlogPlayground.Car –> BlogPlayground.Car –> AssemblyCatalog (Assembly=”BlogPlayground, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”)

Now it fails because MEF required that when we create a type that doesn’t have a default or parameterless constructor, then the constructor should be marked as [ImportingConstructor] and because the constructor requires some additional parts, then we will need to mark the parameters with [Import] as well. So let’s do as the error tells us and fix that as well:

namespace BlogPlayground
{
using System.ComponentModel.Composition;

[Export]
internal class Car
{
private const int WheelCount = 4;

[ImportingConstructor]
internal Car([Import]WheelType wheelTypeType)
{
WheelType = wheelTypeType;
}

internal WheelType WheelType { get; }
}
}

Though if we try to run the test now, it will give us the exact same error as before about not finding a contract for the car. This is where MEF admittedly is a little annoying, what it should have told us now is that it cannot find a contract for the WheelType, so to fix this error we’re going to update that class as well:

namespace BlogPlayground
{
using System.ComponentModel.Composition;

[Export]
internal class WheelType
{
}
}

Now if we were to run our test it would pass. But why the hassle of doing all of this when we could have just solved it with the hardcoded line? And I know it’s not all that different either since we are working with concrete classes. Well, you are right if you asked that, but let’s see now how we can truly tap into the power of MEF.

The magic of MEF

First off let’s make the Car class into an abstract because we would like to work with many different models:

namespace BlogPlayground
{
internal abstract class Car
{
private const int WheelCount = 4;

internal Car(WheelType wheelTypeType)
{
WheelType = wheelTypeType;
}

internal WheelType WheelType { get; }
}
}

Since we can’t instantiate an abstract class, we removed the attributes for MEF. Next, we will create a sports car:

namespace BlogPlayground
{
using System.ComponentModel.Composition;

[Export]
class SportCar : Car
{
[ImportingConstructor]
public SportCar([Import]WheelType wheelTypeType)
: base(wheelTypeType)
{
}
}
}

All well and good, but this won’t work because we want to create a Car but now we have a blueprint for a SportCar. To make it work, we need to tell MEF that this will be exported as a Car as well, to do that we just specify the type in the attribute like so:

namespace BlogPlayground
{
using System.ComponentModel.Composition;

[Export(typeof(Car))]
internal class SportCar : Car
{
[ImportingConstructor]
internal SportCar([Import]WheelType wheelTypeType)
: base(wheelTypeType)
{
}
}
}

But just to make sure, we would want to add another test to make sure:

[Test]
public void CarShouldBeASportCar()
{
Factory sut = new Factory();

Car car = sut.CreateCar();

Assert.That(car, Is.Not.Null, "car instance was not returned from the factory");
Assert.That(car, Is.TypeOf<SportCar>(), "the instance was not of type SportsCar");
Assert.That(car.WheelType, Is.Not.Null, "car instance should have an instance of wheel types");
}

We write this test and it passes on the first try, and we made no change to the factory as well. For such a small code base this doesn’t seem that impressive, but consider using this at the level of services and large applications, the power to change a whole behavior just from an attribute.

Let’s see about adding an engine to the Car but this time we will be using interfaces 😉

Creating the engine

First off we will create an interface for our Engine. We also want to export anything of this type without declaring it explicitly for export. The interface will look like this:

namespace BlogPlayground
{
using System.ComponentModel.Composition;

[InheritedExport]
internal interface IEngine
{
}
}

The [InheritedExport] attribute will export anything that inherits this class as an IEngine.

Now let’s update our Car with the new prerequisite:

namespace BlogPlayground
{
internal abstract class Car
{
private const int WheelCount = 4;

internal Car(WheelType wheelTypeType, IEngine engine)
{
WheelType = wheelTypeType;
Engine = engine;
}

internal WheelType WheelType { get; }

internal IEngine Engine { get; }
}
}

And since this is mandatory, we will need to update the SportCar as well:

namespace BlogPlayground
{
using System.ComponentModel.Composition;

[Export(typeof(Car))]
internal class SportCar : Car
{
[ImportingConstructor]
internal SportCar([Import]WheelType wheelTypeType, [Import]IEngine engine)
: base(wheelTypeType, engine)
{
}
}
}

Since the Engine is just an interface, we will also need to implement it, nothing fancy:

namespace BlogPlayground
{
class SportEngine : IEngine
{
}
}

Notice that as soon as this class was added all the tests are passing again. Do note that an import and an export can only match one to one so if we were to add another engine we would get an error telling us there are more Engines that the container doesn’t know what to do with them.

Though here’s a good spot to show where MEF outshines the competition if you will, and since a Car can’t have several engines, we’re going to move to the features section, so let’s add some features to our car.

Adding features

First, let’s create an interface for the features:

namespace BlogPlayground
{
using System.ComponentModel.Composition;

[InheritedExport]
public interface IFeature
{

}
}

Here we are going to do the same thing with the [InheritedExport] attribute so that we can extend the feature list easily in the future, so let’s create a few features for starters:

namespace BlogPlayground
{
using System.ComponentModel.Composition;

[InheritedExport]
public interface IFeature
{

}

class USB : IFeature
{
}

class GPS : IFeature
{
}

class Radio : IFeature
{
}
}

So let’s update our car to accommodate these features:

namespace BlogPlayground
{
using System.Collections.Generic;

internal abstract class Car
{
private const int WheelCount = 4;

internal Car(WheelType wheelTypeType, IEngine engine, IEnumerable<IFeature> features)
{
WheelType = wheelTypeType;
Engine = engine;
Features = features;
}

internal WheelType WheelType { get; }

internal IEngine Engine { get; }

public IEnumerable<IFeature> Features { get; }
}
}

And now for the implementation, watch the parameters carefully, the [Import] parameters can be satisfied by a single [Export], though an [ImportMany] parameter can be satisfied with more than one [Export]:

namespace BlogPlayground
{
using System.Collections.Generic;
using System.ComponentModel.Composition;

[Export(typeof(Car))]
internal class SportCar : Car
{
[ImportingConstructor]
internal SportCar([Import]WheelType wheelTypeType, [Import]IEngine engine, [ImportMany] IEnumerable<IFeature> features)
: base(wheelTypeType, engine, features)
{
}
}
}

Again the tests have passed but let us make sure that they are all there, let’s add another test:

[Test]
public void CarShouldHaveThreeFeatures()
{
Factory sut = new Factory();

Car car = sut.CreateCar();

Assert.That(car, Is.Not.Null, "car instance was not returned from the factory");
Assert.That(car.Features, Is.Not.Null, "car instance should have a collection of features");
Assert.That(car.Features, Has.Length.EqualTo(3), "the car should have 3 features");
Assert.That(car.Features.ElementAt(0), Is.TypeOf<USB>());
Assert.That(car.Features.ElementAt(1), Is.TypeOf<GPS>());
Assert.That(car.Features.ElementAt(2), Is.TypeOf<Radio>());
}

As we ran this test, we will see that it passed as well. We have now created a way of adding features to our cars without modifying the car, all we need to do is create another feature and implement the IFeature interface.

This is just one of the many features that MEF provides, besides the fact that it’s also extensible, I want to show you one more thing before ending this post since MEF has a lot more to cover than just this, these are just the basics.

Multiple cars?

Let’s say you like your new car so much you want to create one for your friends as well, let’s make an example of that through a new test:

[Test]
public void ShouldBeAbleToCreateMultipleCars()
{
Factory sut = new Factory();

Car car1 = sut.CreateCar();
Car car2 = sut.CreateCar();

Assert.That(car1, Is.Not.Null, "car instance was not returned from the factory");
Assert.That(car2, Is.Not.Null, "car instance was not returned from the factory");
Assert.That(car1, Is.Not.EqualTo(car2), "the two instances should be different");
}

If we run this test it will fail, and mostly because MEF and Dependency Injection, in general, is mostly thought of as having reusable swappable parts, as such when we call the factory to create a second instance, it will return the same instance, but we can change that, all we need to do is the following:

namespace BlogPlayground
{
using System.Collections.Generic;
using System.ComponentModel.Composition;

[Export(typeof(Car))]
[PartCreationPolicy(CreationPolicy.NonShared)]
internal class SportCar : Car
{
[ImportingConstructor]
internal SportCar([Import]WheelType wheelTypeType, [Import]IEngine engine, [ImportMany] IEnumerable<IFeature> features)
: base(wheelTypeType, engine, features)
{
}
}
}

By adding the [PartCreationPolicy] attribute with a CreationPolicy.NonShared, we tell MEF that whenever it creates this part it should create a new instance every time, considering back to our analogy,the axel between two wheels or the frame of the car should be shared, though each wheel should not be shared since we will have 4 of them.

The [PartCreationPolicy] can be applied to both [Import] and [Export] attributes and it can have 3 values and those are Shared, NotShared and Any (by default, if not specified it will be treated as Any) so the combinations between them need to match and the way they can match is as follows:

ImportExportInstance
SharedSharedSingle Instance
SharedNonSharedNo Match
SharedAnySingle Instance
NonSharedSharedNo Match
NonSharedNonSharedSeparate Instance
NonSharedAnySeparate Intance
AnySharedSingle Instance
AnyNonSharedSeparate Instance
AnyAnySingle Instance

Conclusion

I hope you enjoyed the small part of MEF that was presented here, in the future we will look at other nifty features like (but not limited to) metadata, assembly discovery, function exports (yes we can export even just strings and functions even), contracts and lazy initialization, custom exports and these come just out of the box without extending MEF at all.

Here are a few example of how I (and others in the teams I worked in/with) have used MEF in the past and I’m curious what you come up with as well:

  • Making desktop application modules in different assemblies that would load when booting up.

  • Making applications that can download their modules in real time from the server and update without restarting the application.

  • Using it for enabling and disabling access to modules in an application based on roles or other criteria

  • Making functions that plug into the life cycle of the application without touching the core code.

Please note that this will not be a running series but there will be the promised additions to it, I’m mentioning this since MEF might not be the thing you or others are looking for and it would just delay the presentations of the other frameworks.

Thank you and see you next time :),

Vlad V.

2 thoughts on “Let’s talk about MEF – Part 1

  1. Cool introduction! Since you’ve demonstrated that MEF is doable as an IoC with the added benefit of extensibility, I’m wondering how it will be able to penetrate an industry where Castle Windsor or Ninject are prevalent. It sounds to me that for a given project, MEF has to be invested on early to reap its benefits, which might not work for everybody.

    Like

    • Thank you, as for the industry, when it comes to frameworks it will always come down as a matter of taste and usability, for example as an IoC container it is true that it is not as intuitive as the other frameworks, but they also have other goals in mind, though if you want to make plugins for your apps then MEF helps out a lot from assembly loading to part discovery.

      As for the early investment, I tend to agree and disagree as well, ideally, an IoC container, in general, requires some forethought since it’s more of an architectural choice, MEF is no different, and it’s never so easy to update the architectural model, although they have kind of become a standard, look at ASP.NET Core It’s built on top of dependency injection. Though with the help of automated testing and a good abstract design it shouldn’t be that difficult, though I cannot grade it on its difficulty since again it comes down to how well you take advantage of what the framework has to offer.

      A good approach to introducing new systems into an older code base is to always add and change what is needed. If you do an overhaul of the system, and that system is not properly tested, you run the risk of breaking something.

      Like

Leave a comment