Unity, Part 9: Integration With Managed Extensibility Framework

This time, I will be talking about integrating Unity with Managed Extensibility Framework (MEF). You can find the other posts in the series here (how to use Unity in a web application), here (adding Interfaces), here (registration by convention), here (injecting values), here (extensions), here (aspect-oriented programming), here (dependency injection) and the first one here (introduction).

The Managed Extensibility Framework (MEF) has been around since the release of .NET 4.0, and even before as a beta, stand-alone package. Basically, it provides an extensible mechanism for detecting and loading plugins. It’s easier to use than the similarly-named Managed Add-In Framework (MAF), and even if it’s not so feature-rich (it doesn’t support sandboxing, for once), unlike MAF, it is well alive!

So, what does MEF offer that can be of use to Unity? Well, MEF knows how to locate exports/plugins from a number of locations, like assemblies and file system directories. It’s just a matter of finding the exports we’re interested in and registering them with Unity.

An export in MEF is some class that is decorated with an ExportAttribute (technically speaking, this is just when using the Attributed Programming Model, since .NET 4.5 there is also the Convention-Based Programming Model). This attribute allows specifying the type to export (ContractType) and also the contract name (ContractName). This matches closely the Unity/IoC concept of contract type and name.

We could find all exports under a given path using MEF using an AssemblyCatalog, a particular implementation of a ComposablePartCatalog:

   1: var catalog = new AssemblyCatalog("some path");

A couple of helper functions for picking up the export’s contract type and name, by leveraging the ReflectionModelServices class:

   1: public static IDictionary<String, Type> GetExportedTypes<T>(this ComposablePartCatalog catalog)
   2: {
   3:     return (GetExportedTypes(catalog, typeof(T)));
   4: }
   5:  
   6: public static IDictionary<String, Type> GetExportedTypes(this ComposablePartCatalog catalog, Type type)
   7: {
   8:     return (catalog.Parts.Where(part => IsComposablePart(part, type) == true).ToDictionary(part => part.ExportDefinitions.First().ContractName, part => ReflectionModelServices.GetPartType(part).Value));
   9: }
  10:  
  11:  
  12: private static Boolean IsComposablePart(ComposablePartDefinition part, Type type)
  13: {
  14:     return (part.ExportDefinitions.Any(def => (def.Metadata.ContainsKey("ExportTypeIdentity") == true) && (def.Metadata["ExportTypeIdentity"].Equals(type.FullName) == true)));
  15: }

This will return a collection of key-value pairs, where the key is the contract name and the value the contract type; this is so there can be multiple contract names for a given contract type. After we have this, it’s just a matter of iterating the results and registering each occurrence:

   1: var type = typeof(ISomeType);
   2: var exports = catalog.GetExportedTypes(type);
   3:  
   4: foreach (var entry in exports)
   5: {
   6:     unity.RegisterType(type, entry.Value, entry.Key);
   7: }

So, given the following contract and implementations:

   1: public interface ISomeType
   2: {
   3:     void SomeMethod();
   4: }
   5:  
   6: [Export("Some", typeof(ISomeType))]
   7: public class SomeImplementation : ISomeType
   8: {
   9:     public void SomeMethod() { }
  10: }
  11:  
  12: [Export("Another", typeof(ISomeType))]
  13: public class AnotherImplementation : ISomeType
  14: {
  15:     public void SomeMethod() { }
  16: }

We can obtain a specific contract type implementation given it’s name:

   1: var myImplementation = unity.Resolve<ISomeType>("MyName");

And also all implementations of the contract that were found:

   1: var all = unity.ResolveAll<ISomeType>();

This can be enhanced in a couple of ways:

  • Use a Unity extension to automatically find and register exports at runtime;
  • Make use of MEF metadata to tell Unity which lifetime managers to use, and other useful properties, such as the default implementation for the contract type.

As usual, I’m looking forward for your comments!

                             

No Comments

Add a Comment

As it will appear on the website

Not displayed

Your website