Monday, April 12, 2010

MEF and IoC/DI (6)

Let's look my third API class - MEFWrapper.

MEFWrapper Class


The above two classes not only make the DI mappings easy, but they also try to expose MEF rich infrastructure as minimum as possible. How to load this DI information to MEF? This comes to the third class, MEFWrapper. The same applies to the MEFWrapper class. This class encapsulates the logic of how to create MEF's container and how add composable parts to the container.

Steps to Load DI Information


With this class, there are three steps to load DI information to MEF. The first step is get an instance of MEFWrapper through the static method CreateInstance(). This follows singleton pattern, to create a single MEF container instance per application.

The second step is to add DICatalog instances through Add() or AddRange() interfaces.

After all the DI information are added to MEFWrapper, the third step is to call the method of InitialzeDIMappings(), which encapsulates the logic of loading DI parts and catalogs to MEF container.

Get Mapped Instance


Now your MEF framework is ready for use. You can use MEF's Import attribute to let MEF to inject instances for your usage. MEFWrapper also provides static methods of GetInstance() and GetInstance(key) to explicitly retrieve a mapped instance from MEF.

Dispose MEFWrapper Instance


After your usage or your application is going to be terminated, you should call the method of dispose() (IDisposable implementation) of the MEFWrapper instance.

Here is an example of using this wrapper class in a DIRootCatalog class:
public class DIRootCatalog : DICatalogBase {
  private static MEFWrapper _instance = null;

  # region CTOR
  private DIRootCatalog() :
    base (Assembly.GetExecutingAssembly())
  { }
  # endregion

  public static void LoadDIMappings(){
    // Create instance and load DIs only once
    if (_instance == null) {
      _instance = MEFWrapper.GetIntance(new DIRootCatalog());
      // Exampels to add DIs to instance
      // Assume DIs are based on DICatalogBase
      _instance.Add(new DIDataReader());
      _instance.Add(new DIProcessorController());
      _instance.AddRange(
        new DICatalogBase[]{
          new DILog(), new DIDBService() }
        );
      _instance.Add(new DICatalogBase("DIExtensions"));
      // Initialze MEF Container with DI parts through catalogs
      _instance.InitializeDIMappings();
    }
  }

  public static void UnLoadDIMappings() {
    if (_instance != null) {
      _instance.Dispose();
      _instance = null;
    }
  }
}

...
internal class DIResolver : DIResolverBase {
    // Define Import and Export properties
  ...
}


And there is an example of a console application where the above DIRootCataLog is used:
class Program {
  static void Main(string[] args) {
    // Load MEF framework with DI mappings
    DIRootCatalog.LoadDIMappings();
    // Get process controler instance from MEF
    var mainProcess = MEFWrapper.GetInstance<IProcessController>();
    // Start process
    mainProcess.Start();
    // Unload MEF framework
    DIRootCatalog.UnLoadDIMappings();
  }
}



Here is the library of DICommonLibrary project.

Note: the project depends on two library files: one is MEF library and another is a related open source library for MEF. Both are available from CodePlex:

System.ComponentModel.Composition.dll
Microsoft.Practices.ServiceLocation.dll

0 comments: