Search code examples
c#dependency-injectionunity-containermefcomposite

How to inject N MEF exports into 1 Unity composite service using MefContrib or other technique?


Let's say I have 5 separate assemblies with the following (assume the class name is different in each):

[Export(typeof(IService))]
public class Service: IService
{
    // ...
}

And I have a class that will be a composite of these in my main assembly

public class CompositeService : IService
{
    public CompositeService(IEnumerable<IService> services)
    {
        // ...
    }
}

What I would like to do is have the Unity container resolve the CompositeService for the IService and have the MefContrib extension for Unity go and find the 5 other exports and inject them into CompositeService's constructor.

The problem is that you can't have N instances for a nameless unityContainer.RegisterType<IService> nor can you for named instances if they all have the same name.

I think I'm missing something simple in the combination of the 2 technologies (Unity + MEF) via the third (MefContrib) but can't seem to pick up on what it is.

Is this possible or is there a workaround? Eventually, I'm going for full bi-directional dependency injection and dynamic component discovery.


Solution

  • I think what is likely the best approach is to flip this around. Instead of trying to register your components via Unity, you actually leave the discovery of these parts to MEF. MEFContrib includes an Unity integration mechanism that allows your MEF composed parts to be injected into Unity components. This was original detailed at Piotr WŁodek's blog, whereby he also gives you a sample. Essentialy, the way it works is you can use a series of extension methods on your UnityContainer to register your catalogs. Internally, it will create the appropriate extension and wire up your container.

    Here is a quick and dirty example, we'll create some interfaces:

    public interface IUnityComponent
    {
      IEnumerable<IMefComponent> MefComponents { get; }
    }
    
    public interface IMefComponent
    {
      string Name { get; }
    }
    

    And then some sample parts which we'll export (via MEF):

    [Export(typeof(IMefComponent))]
    public class MefComponent1 : IMefComponent
    {
      public string Name { get { return "MEF Component 1"; } }
    }
    
    [Export(typeof(IMefComponent))]
    public class MefComponent2 : IMefComponent
    {
      public string Name { get { return "MEF Component 2"; } }
    }
    

    Now, we'll create another part (this will be created via Unity):

    public class UnityComponent : IUnityComponent
    {
      public UnityComponent(IEnumerable<IMefComponent> mefComponents) 
      { 
        // mefComponents should be provided from your MEF container.
        MefComponents = mefComponents;
      }
    
      public IEnumerable<IMefComponent> MefComponents { get; private set; }
    }
    

    To wire it all up, we simply need to use the RegisterCatalog extension method on your UnityContainer (import MefContrib.Integration.Unity after you've added a reference to MEFContrib):

    var container = new UnityContainer();
    
    // Register the catalog - this handles MEF integration.
    container.RegisterCatalog(new DirectoryCatalog("."));
    
    // Register our Unity components.
    container.RegisterType<IUnityComponent, UnityComponent>(new ContainerControlledLifetimeManager());
    

    Now you should be able to grab the instance and enumerate the MEF-provided parts:

    // Grab an instance of our component.
    var instance = container.Resolve<IUnityComponent>();
    foreach (var mefComponent in instance.MefComponents)
    {
      Console.WriteLine(mefComponent.Name);
    }
    

    note: 100% untested.