views:

158

answers:

2

My application is using MEF to export some classes from an external assembly. These classes are setup for constructor injection. The issue I am facing is that MEF is attempting to instantiate the classes when I try to access them. Is there a way to have Ninject take care of the instantiation of the class?

IEnumerable<Lazy<IMyInterface>> controllers = 
    mefContainer.GetExports<IMyInterface>();

// The following line throws an error because MEF is 
// trying to instantiate a class that requires 5 parameters
IMyInterface firstClass = controllers.First().Value;

Update:

There are multiple classes that implement IMyInterface and I would like to select the one that has a specific name and then have Ninject create an instance of it. I'm not really sure if I want laziness.

[Export(typeof(IMyInterface))]
public class MyClassOne : IMyInterface {

     private MyRepository one;
     private YourRepository two;

     public MyClassTwo(MyRepository repoOne, YourRepository repoTwo) {
            one = repoOne;
            two = repoTwo;
     }         
}

[Export(typeof(IMyInterface))]
public class MyClassTwo : IMyInterface {

     private MyRepository one;
     private YourRepository two;

     public MyClassTwo(MyRepository repoOne, YourRepository repoTwo) {
            one = repoOne;
            two = repoTwo;
     }


}

Using MEF, I would like to get either MyClassOne or MyClassTwo and then have Ninject provide an instance of MyRepository and YourRepository (Note, these two are bound in a Ninject module in the main assembly and not the assembly they are in)

A: 

You can use ExportFactory to create Instances see docs here:

http://mef.codeplex.com/wikipage?title=PartCreator

Your case would be slitly different I would use Metadata and a custom attribute also

[ImportMany(AllowRecomposition=true)] 
    IEnumerable<ExportFactory<IMyInterFace, IMyInterfaceMetaData>> Controllers{ get; set; } 

public IMyInterface CreateControllerFor(string parameter)
{
var controller = Controllers.Where(v => v.Metadata.ControllerName == parameter).FirstOrDefault().CreateExport().Value; 
            return controller; 
}

or use return Controllers.First() without the Metadata

Then you can code the ninject parts around that or even stick with MEF Hope this helps

silverfighter
The `ExportFactory` type is only available for Silverlight.
Baddie
+1  A: 

You could use the Ninject Load mechanism to get the exported classes into the mix, and the you either:

kernel.Get<IEnumerable<IMyInterface>>()

The creation is lazy (i.e., each impl of IMyInterface is created on the fly as you iterate over the above) IIRC, but have a look at the tests in the source (which is very clean and readable, you have no excuse :P) to be sure.

If you dont need the laziness, use IMyInterface[] or IList<IMyInterface>

or you can use the low-level Resolve() family of methods (again, have a look in the tests for samples) to get the eligible services [if you wanted to do some filtering or something other than just using an instance - though binding metadata is probably the solution there]

Finally, if you can edit in an explanation of whether you need laziness per se or are doing it to illustrate a point. (and have a search for Lazy<T> here and in general wrt both Ninject and autofac for some samples - cant recall if there are any examples in the source - think not as it's still on 3.5)

EDIT: In that case, you want a bind that has:

Bind<X>().To<>().In...().Named( "x" );

in the registrations in your modules in the child assembly.

Then when you're resolving in the parent assembly, you use the Kernel.Get<> overload that takes a name parameter to indicate the one you want (no need for laziness, arrays or IEnumerable). The Named mechanism is a specific (just one or two helper extensions implement it in terms of the generalised concept) application of the binding metadata concept in Ninject - there's plenty room to customise it if somethng beyond a simple name is insufficient.

If you're using MEF to construct the objects, you could use the Kernel.Inject() mechanism to inject properties. The problem is that either MEF or Ninject - has to find the types (Ninject: generally via Bind() in Modules or via scanning extensions, after which one can do a Resolve to subset the bindings before instantiation - though this isnt something you normally do) - has to instantiate the types (Ninject: typically via a Kernel.Get(), but if you discovered the types via e.g. MEF, you might use the Kernel.Get(Type) overloads ) - has to inject the types (Ninject: typically via a Kernel.Inject(), or implicit in the `Kernel.Get())

What's not clear to me yet is why you feel you need to mix and mangle the two - ultimately sharing duties during construction and constructor injection is not a core use case for either lib, even if they're both quite composable libraries. Do you have a constrait, or do you have critical benefits on both sides?

Ruben Bartelink
Updated answer with some more info. Also, could you provide the link to the test you're referring to. I can't seem to find them.
Baddie
@Baddie: I reckon you updated the 'answer' :D I updated mine (with more questions!) Re the tests I'm referring to, I'd be doing a get of the ''full'' trunk and then doing a find in files for IEnumerable and/or the word lazy (think some of the `[Fact]`s have something like resolution should be lazy in the title) NB this isnt what you want any more based on your clarifications.
Ruben Bartelink
Although using the `Named` method works fine for me, I wouldn't be using MEF to discover these classes.
Baddie
@Baddie: So are you sorted then? Do you need MEF in the picture or are you happy using just Ninject? Are you still looking for a pure MEF solution? Anything else unclear?
Ruben Bartelink