Dependency Injection Using the MEF Framework

Introduction

The Managed Extensibility Framework (MEF) has solved the common problems encountered when developing enterprise applications. It’s a new library introduced in the .NET Framework 4.0, which is essentially an IOC container. MEF also addresses the problem of simplifying the design of extensible applications and components. In this article, I will explain the importance of MEF and where can MEF be applied during dependency injection and plug-in creation.

Problems MEF Has Solved

MEF solved the runtime extensibility problem. By using MEF, any application can work on a plug-in model that needs to create its own infrastructure from scratch. Plug-ins created by using MEF will often be application-specific and cannot be reused across multiple implementations.

  • MEF provides a standard way for the host application to expose itself and consume external extensions.
  • MEF also offers a set of discovery approaches for the application to locate and load available extensions.
  • MEF allows developers tagging extensions with additional metadata, which aims to facilitate rich querying and filtering.

A Sample Application Using MEF

MEF provides a built-in set of elements that allows developers to “export” and “import” objects across projects. These “export” and “import” tags allow developers not to rely on hard dependencies. This is shown in Figure 1.

New Console Application
Figure 1: New Console Application

To demonstrate MEF “export” and “import” functionalities, I have created a Console Application by clicking New Project from the Start page of Visual Studio. It will open the New Project pop-up, as you saw in Figure 1. I have named the project ‘PrjMEF’ and OK. This will create a new console application project (see Figure 2).

Added reference
Figure 2: Added reference

To use MEF in the previously created console application, I have added the following reference in the project: System.ComponentModel.Composition.

Next, I have defined a container. In that container, all the exported values will be stored. One simple way to do that is to create a class, as mentioned in the following code snippet.

public static class MefInjection
{
   private static CompositionContainer mycontainer;
   public static CompositionContainer MyContainer
   {
      get
      {
         if (mycontainer == null)
         {
            var catalog =
               new DirectoryCatalog(".", "MyMEFProject.*");

            mycontainer = new CompositionContainer(catalog);

         }

         return mycontainer;
      }
   }
}

The preceding code will grab all the exported values from all the assemblies in the same directory starting with “MyMEFProject”. Then, I can annotate the classes as mentioned in the following code snippet. The ImportingConstructor attribute will allow us to import objects while I create the instance.

   [Export]

   public class Logger
   {
   }

   [Export]
   public class MyService
   {
      private Logger log;

      [ImportingConstructor]
      public MyService(Logger log)
      {
         this.log = log;
      }
   }

When I need an instance of MyService Object, I can request it from the container, as in the following code snippet. In the previous MyService class, I have a field with an [Import] attribute. This means MEF will resolve the value for me while it is retrieving the exported value for MyService.

MyService myService = MefInjection.Container.GetExportedValue
   <MyService>();

We can have multiple exports, but the way you need to handle them is different. For example, to have a screen with several tabs that are exported, refer to the following code snippet.

public interface ITab { }

[Export(typeof(ITab))]
public class HomeTab : ITab { }

[Export(typeof(ITab))]
public class GamesTab : ITab { }

[Export(typeof(ITab))]
public class WishlistTab : ITab { }

Finally, the next code snippet shows the entire console application code.

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PrjMEF
{
   class Program
   {
      static void Main(string[] args)
      {
      }
   }

   public static class MefInjection
   {
      private static CompositionContainer mycontainer;
      public static CompositionContainer MyContainer
      {
         get
         {
            if (mycontainer == null)
            {
               var catalog = new DirectoryCatalog(".",
                  "MyProjectNamespace.*");

               mycontainer = new CompositionContainer(catalog);

            }

            return mycontainer;
         }
      }
   }

   public interface ITab { }

   [Export(typeof(ITab))]
   public class HomeTab : ITab { }

   [Export(typeof(ITab))]
   public class GamesTab : ITab { }

   [Export(typeof(ITab))]
   public class WishlistTab : ITab { }

   [Export]
   public class Home
   {
      [ImportMany]
      private List<ITab> tabs;
   }

   [Export]
   public class Logger
   {
   }

   [Export]
   public class MyService
   {
      private Logger log;

      [ImportingConstructor]
      public MyService(Logger log)
      {
         this.log = log;
      }
   }


}

Conclusion

MEF is a powerful framework for creating extensible applications, and should definitely be taken into consideration when designing an application. I hope this article was helpful! That’s all for today; happy reading!

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read