3
votes

I have an Import that is not working - the object is null. Originally it was an ImportMany but I simplified it down to an Import to try to identify the issue but I haven't been successful in doing so.

I've gone through this site and Google and followed the main ideas:

  • Don't instantiate the class yourself, let MEF do it, otherwise call container.getExport() - still doesn't work
  • Put an [Export] on the class containing the [Import] property otherwise it won't be picked up as a part by the container composition process (confirmed when debugging).

My code set up is as follows (simplified for the sake of compactness):

Assembly1

public class MyBootstrapper
{
    //Automatically called by ExcelDna library, I do not instantiate this class
    public void AutoOpen()
    {
        var ac1 = new AssemblyCatalog(typeof(XLHandler).Assembly);
        var ac2 = new AssemblyCatalog(typeof(MyComponent).Assembly);

        var agc = new AggregateCatalog();
        agc.Catalogs.Add(ac1);
        agc.Catalogs.Add(ac2);

        var cc = new CompositionContainer(agc);

        try
        {
            cc.ComposeParts(this);
        }
        catch (CompositionException exception) {}
    }
}

[Export]
public class XLHandler
{
    [Import(typeof(IMyComponent))]
    public IMyComponent _component;

    public void SomeMethod()
    {
        //try to use _component but it is null
    }
}

Assembly2

public interface IMyComponent
{
    //stuff...
}

Assembly3

[Export(typeof(IMyComponent)]
public MyComponent : IMyComponent
{
    //more stuff...
}

Anybody know/have an idea as to why the _component variable in XLHandler is not injected into by the MEF container?

Do I need to Export/create an AssemblyCatalog for the Interface in Assembly2?

2
Not 100% sure about this, but shouldn't the import attribute be [Import(typeof(IMycomponent))]?p.s.w.g
Yes, you are exporting as IMyComponent so you must also import as this. You can remove the typeof definition from the import because your variable type is already IMyComponent.ChrisO
Yup, that was a typo in the Q. I'll fix that.clicky

2 Answers

8
votes

When importing parts, you can either use the [Import] attribute on a Property, or request it as part of the Constructor and use an [ImportingConstructor] attribute.

Any part imported using the [Import] attribute will not be available in the class's constructor

So in your case, change the XLHandlerclass like this:

[Export]
public class XLHandler
{
    [ImportingConstructor]
    public void SomeMethod(MyComponent component)
    {
        _component = component;
       // You can use _component, since it has already been resolved...
    }
}
2
votes

In MyBootstrapper.AutoOpen you need to replace:

cc.ComposeParts(this);

with something like:

var handler = new XLHandler();
cc.ComposeParts(handler);

or:

var handler = cc.GetExportedValue<XLHandler>();

You cannot compose the parts of MyBootstrapper since it has not imports. ComposeParts does nothing.

Another approach is to add an import to MyBootstrapper. Like:

public class MyBootstrapper
{
    [Import]
    XLHandler XLHandler;

    //Automatically called by ExcelDna library, I do not instantiate this class
    public void AutoOpen()
    {
        //Leave your implementation unchanged.
    }
}

By the way MyComponent does not compile.