开发者

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

开发者 https://www.devze.com 2023-04-11 12:22 出处:网络
Let\'s say I have 5 separate assemblies with the following (assume the class name is different in each):

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> service开发者_如何学JAVAs)
    {
        // ...
    }
}

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.


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.


Just tried the same solution from Matthew here and it is working ok, Unity is picking up the exports from MEF and injecting them into the constructor (which accepts an IEnumerable<>).

Don't know if it can help you, but including both MefContrib and MefContrib.Integration.Unity can help: for a while I only had the latter included and encountered similar errors.

As a side note, keep in mind that all the registrations in Unity (coming from MEF exports) will be "nameless" so if you try ResolveAll<> you will get an empty collection and if you try Resolve<> you will get an exception if there is more than 1 implementation registered.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号