Tuesday, 29 September 2009

MEF: Getting Started

One of my side-projects (“Tomato Timer”) has plugins as a central design characteristic. Now, I have never built an application that relies on plugins before – so when it came to thinking about what framework I could use – MEF was an obvious strong candidate.

What is MEF?

MEF stands for “Managed Extensibility Framework”. It’s a framework developed by Microsoft for .NET developers to allow them to easily pull components out from the main compiled assembly, and dynamically “compose” them at run time.

This behaviour is shared amongst most modern IoC Containers and is a very powerful pattern. The ability to easily swap out components not only facilitates plugins, but ease of testability, maintenance and improved design.

Why Did I Choose MEF?

I decided to go with MEF because:

  • I have never worked with it before.
  • I want to compare it’s usage against IoC containers.
  • I like saying “I am doing MEF” on the phone to my non-geeky friends who then get concerned for my welfare and start telling me to “talk to someone”.

Basic MEF Terminology

Here’s a quick run-down of the terms you will see when first getting up and running with MEF:

Imports

“Imports” are basically in inputs to your application from the outside world. This essentially says to MEF: “I want you to find me some code that tells me it can give me X”.

   1: // Find code that can give us a List of Strings.
   2: [Import(typeof(List<string>))]
   3: List<string> ImportedStringList { get; private set; }

Note in the above code all we have really done is decorate a property that we would likely already have in our code.

I personally do not like the fact that we need to specify the type to the attribute, but I guess the MEF team have their reasons. :)

Exports

The exact opposite to Imports, Exports are the outputs of your code. These work in tandem with the Imports to glue things together. When you ask for an Import(typeof(T)], MEF will run off to find code that has a method that returns “T” that is decorated with an Export attribute.

   1: // Declare that we can satisfy the previous Import
   2: // by returning a List<string>
   3: [Export(typeof(List<string>))]
   4: public List<string> GenerateStringList() { /*...*/ }

Catalogue

Or “Catalog” for our friends across the pond :)

The catalogue is essentially the code that is searched for Exports to use for Imports. The two most common are “AssemblyCatalog” (which scans an assembly) and “DirectoryCatalog” (which scans a given directory).

   1: // Get All Exports in the Current Assembly
   2: var asmCat = new AssemblyCatalog(
   3:     Assembly.GetExecutingAssembly());
   4: // Get All Exports from the "Plugins" Directory
   5: // (relative to the application directory)
   6: var dirCat = new DirectoryCatalog("Plugins");

Container

The container (or Composition Container) is basically the holding area for the types that are loaded via MEF. In most applications you may only have one of these - but it is possible to have more than one as well as nest them (useful for defining hierarchies or managing scope).

   1: // Create a new Container based on
   2: // the Current AssemblyCatalog
   3: var asmCat = new AssemblyCatalog(
   4:     Assembly.GetExecutingAssembly());
   5: var container = new 
   6:     CompositionContainer(asmCat);

Composition

The process by which MEF discovers the types available and initialises them is known as “composition”. We ask our Container to “ComposeParts” which will then scan the catalogues we have added to the container for types.

   1: // Ask the Container to begin Composing
   2: // based on the Catalogues available.
   3: container.ComposeParts(this);

Note the reference to “this” in the method call, this is to basically associate our client code with the container (since this is where the imports are specified).

Initial Thoughts

I personally still have a lot to learn with MEF, but I can tell you this:

  • I had built a basic MEF application from start to finish in 1 tomato (25 minutes). This was essentially a basic string transformer which also used re-composition to pick up new plugins at runtime without a restart.
  • The syntax is relatively clean – you don’t need to do much to get your objects.
  • I like the fact you can get the source on CodePlex.
  • It’s working pretty damn good and still only in preview (7 at time of writing).
  • They have some great people that offer a lot of support on the team both in the discussions and on twitter (e.g. Glenn Block or Nicholas Blumhardt).
  • I have completed most of the core plugin code for Tomato Timer that I was working on, MEF made integrating it really easy!

Work Hard. Play Harder.

No comments:

Post a Comment