Support for ResolveAll() and generic ResolveAll<>()

May 4, 2010 at 1:06 PM

Hi,

I have tested integration of MEF to Unity 2.0 and all works fine assuming I use container's Resolve() method.

When I try to use method ResolveAll for resolfing all named type registrations for a given type, container returns an empty collection.

Is there support for ResolveAll method?

 

Thank you in advance

Coordinator
May 16, 2010 at 1:59 PM

Hello,

The ResolveAll method in Unity resolves only named types registered in the container itself. Thus, it is not a good method to use. Recently, we have equipped the Unity to support Lazy<T>, IEnumerable<T> and IEnumerable<Lazy<T>>. So now, if you want to resolve ALL (not only named) types registered in the Unity IoC and MEF use this:

var components = unityContainer.Resolve<IEnumerable<Lazy<IComponent>>();

You can read about Lazy<T> and IEnumerable<T> support for Unity 2.0 here.

Hope this helps.

Piotr

May 18, 2010 at 8:27 AM

Hello,

Thank you for your answer! I have tried your tip with IEnumerable and it works like a charm but I am stuck at another issue:

I have code like this:

[Export(typeof(IModule))]
public class MyModule : IModule
{}


var con = new UnityContainer();
con.AddNewExtension<CompositionIntegration>();
con.RegisterType<IModule, MyModule>();

var items = con.Resolve<IEnumerable<IModule>>();
var items2 = con.Resolve<IEnumerable<IModule>>();
var items3 = con.Resolve<IEnumerable<IModule>>();

The first occurence of Resolve gives two instances of MyModule type, second one three instances and the third one four instances.
When I remove Export attribute, all occurences give just one element.

I need Export attribute on MyModule class because I use RegisterCatalog extension at another place of my project.

Can you give me some hint ?

Thanks,
Pavel

Coordinator
May 18, 2010 at 10:53 AM

Thanks for reporting this. Unfortunately, as of now, we don't support the registration of the the same type both in MEF and the IoC. One workaround is to either export MyModule under different contract (I mean named contract) or remove the IoC registration.

What is your target scenario for registering the same type both in MEF and IoC ? Note, that you can use bi-directional sync. In this case, a type registered in MEF will be available to IoC and any type registered in the IoC will be automatically available to MEF.

Regards,

Piotr

May 18, 2010 at 11:27 AM

Hi,

I donť fully understand where runs the registration to MEF? Is it done automatically during calling RegisterType or Resolve action (if registered/resolved type has Export atribute)?
I am not registering same type manualy in both MEF and Unity. I call RegisterCatalog at different place in code to different instance of UnityContainter (but for the same type).

P.

Coordinator
May 18, 2010 at 11:55 AM

If you use CompositionIntegration Unity extension, which is a one way integration MEF->Unity (Unity can resolve MEF parts but not the opposite), a CompositionContainer is created under the hoods. In the code provided you tag MyModule class with an Export attribute, which makes your class immediately available to MEF, and at the same time you register the same class within Unity. This won't work now. Btw, why would you do that ? Do you use RegisterCatalog extension method on the IoC ? Consider registering the MyModule class either in MEF or IoC.

Regards,

Piotr

May 18, 2010 at 12:41 PM

Ok, let's explain my scenario. Imagine I have two implementations of Registrator class, each of them registrates modules (class implementing IModule interface) into UnityContainer.
One of them registrates types using MEF  - creates DirectoryCatalog with all types marked with Export atribute and this catalog integrates through your extension RegisterCatalog
to UnityContainer. Other implementation registers the SAME types in a different way - directly into IoC through RegisterType. The registration process always uses only one type of Registrator implementation at the same time.

The problem comes into play when I want to resolve all types registered in IoC/MEF (implementing given interface - IModule) with no idea which one of registrators was used to register types in container.

Ho can I resolve all types with given interface?

Regards,

Pavel

Coordinator
May 18, 2010 at 1:13 PM
Edited May 18, 2010 at 3:50 PM

So basically, you have a collection of Modules in your app. Now you want to register them. Here's the code:

 

public interface IModule {}

[Export(typeof(IModule))]
public class Module1 : IModule {}

public class Module2 : IModule {}

[Test]
public void Test()
{
    // Setup
    var unityContainer = new UnityContainer();
    var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());

    unityContainer.RegisterCatalog(assemblyCatalog);
    unityContainer.RegisterType<IModule, Module2>();

    var modules = unityContainer.Resolve<IEnumerable<IModule>>();
    Assert.That(modules.Count(), Is.EqualTo(2));

    var modules2 = unityContainer.Resolve<IEnumerable<IModule>>();
    Assert.That(modules2.Count(), Is.EqualTo(2));
}

 

 

You have 2 modules, namely Module1 and Module2. Module1 gets registered by MEF, Module2 is registered via IoC. Once you pull the IModule from IoC, you're gonna get both  IModule implementations. What was wrong with your last code was the fact that you had exported MyModule via MEF and registered THE SAME class within an IoC AT THE SAME time. You can register implementations of the same interface with both Unity and MEF at the same time only when the concrete implementations vary.

Is that what you wanted to do ?

BTW, did you use the latest source code from github?

Cheers,

Piotr

May 18, 2010 at 2:25 PM
Edited May 18, 2010 at 2:25 PM

Thanks for example. I have downloaded sources from github yesterday.

I understand what You are trying to tell me, I cannot register the same by MEF and IoC at the same time. I don't want to.
But what I don´t know how to do it when I want to expose Module1 to be available for MEF registration and at the same type to be available for IoC registration.

 

        public interface IModule { }
public interface IRegistrator
{
void Register(IUnityContainer container);
}

[Export(typeof(IModule))]
public class Module1 : IModule { }

[Export(typeof(IModule))]
public class Module2 : IModule { }

public class RegistratorMef : IRegistrator
{
public void Register(IUnityContainer container)
{
var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
container.RegisterCatalog(assemblyCatalog);
}
}
public class RegistratorIoC : IRegistrator
{
public void Register(IUnityContainer container)
{
container.RegisterType<IModule, Module1>();
container.RegisterType<IModule, Module2>();
}
}
[Test]
public void Test()
{
// Setup var unityContainer = new UnityContainer();

// Registration process is doing through configuration so I don't know which instance of registrator I actually get - here I simulate it with comment //unityContainer.RegisterType<IRegistrator, RegistratorMef>(); unityContainer.RegisterType<IRegistrator, RegistratorIoC>(); var registrator = unityContainer.Resolve<IRegistrator>();

registrator.Register(unityContainer);
           var modules = unityContainer.Resolve<IEnumerable<IModule>>();
Assert.That(modules.Count(), Is.EqualTo(2));

var modules2 = unityContainer.Resolve<IEnumerable<IModule>>();
Assert.That(modules2.Count(), Is.EqualTo(2));
}

When I run test like this, it throw exception during Resolve because there is no registration of IEnumerable strategy to Unity (no AddNewExtension<CompositionIntegration>(); or RegisterCatalog).
By adding unityContainer.AddNewExtension<CompositionIntegration>() it enables me to Resolve<IEnumerable<<IModule>> but gives bad result (duplication).

When I uncomment the line which choose RegistratorMef (and comment other one) it works as I expect.

 

Regards,
Pavel

 

Coordinator
May 18, 2010 at 3:56 PM

Thank you for clarifying the problem! You definitely found a bug. The bug has been fixed, please update you MefContrib sources. After the bug fix, it is now possible to register the same types in both MEF and the IoC and have them resolved. Please let me and others know if your problem has been solved.

Regards,

Piotr

May 18, 2010 at 6:30 PM

Hi Piotr,

I tested your fix and I have to say bravo to you and thanks for your effort! It works now very well.
One more question (I promise the last for now :-) When I run both registrators at the same time (I know I said I don't need it) and then Resolve I get three items in collection (Module2 instance twice) - actually I found bug in my code presented where IoC obviously doesn't allow two default registrations for a type so the second call to RegisterType overwrites the first one line before - so is the explanation for count of 3. But the question is if your fix was meant to allow this or not (as you have said in previous posts).

Thank you very much,

Pavel

Coordinator
May 18, 2010 at 6:43 PM

I knew I had missed something ;) You are right - there was a bug in you code concerning registration in the IoC. The answer to your question is yes. You can run both registrations at the same time and this will work just fine!

Glad I could help!

 

Piotr