tags:

views:

87

answers:

1

I'm trying to figure out why one of my objects does not seem to be satisfying its Import. I think it may be the way I am using the container.ComposeParts() function but I have not been able to find much documentation with regards to it.

I have four projects
MEF.Service.Contracts
MEF.Service.Messaging (implements contracts)
MEF.Service.Core
MEF.Service.Console

MEF.Service.Contracts contains a simple interface called IMessageService with one function

public interface IMessageService
{
    void SendMessage(string message);
}

MEF.Service.Messaging has one implementation of the above

[Export(typeof(IMessageService))]
public class ConsoleMessageService : IMessageService
{
    #region IMessageService Members

    public void SendMessage(string message)
    {
        Console.WriteLine(message);
    }

    #endregion
}

MEF.Service.Core has a class called ServiceManager that imports available services. In this example the IMessageService

public class ServiceManager
{
    [Import]
    public IMessageService MessageService { get; set; }
}

Finally, in the MEF.Service.Console application project I am creating the MEF container using a DirectoryCatalog. Then I create an instance of ServiceManager and call its MessageService property.
However at this point it fails with an object reference error.

Here is the code in the MEF.Service.Console project

class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();
        p.Run();
    }

    public void Run()
    {
        Compose();

        ServiceManager manager = new ServiceManager();
        manager.MessageService.SendMessage("Test Message");

        Console.ReadLine();
    }

    private void Compose()
    {
        var catalog = new DirectoryCatalog(@".\");
        var container = new CompositionContainer(catalog);
        container.ComposeParts(this);
    }
}

MEF.Service.Console has references to the other three projects just to ensure the dlls are in the same folder during runtime.

I've examined the catalog and container after they are initialized and it does contain my ConsoleMessageService export as a part.

I'm trying to figure out why my [Import] MessageService in my ServiceManager is not getting satisfied.

Any help or pointers on composing parts and how Imports get satified would be appreciated.

+1  A: 

I'm pretty new to MEF myself, but what I see here is this: you don't have the IMessageService as an instance of your main app - instead, it's on a separate object ServiecManager, that you create dynamically after the container.ComposeParts has been called...

My guess: MEF doesn't get a chance to satisfy the import on the ServiceManager since that object isn't around at the time of the composition.

Suggestion: add a IMessageService instance to your main app and let MEF handle the import, and then pass that instance into your ServiceManager - something like this:

class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();
        p.Run();
    }

    [Import]
    IMessageService MessageService { get; set; }

    public void Run()
    {
        Compose();

        ServiceManager manager = new ServiceManager(MessageService);
        manager.MessageService.SendMessage("Test Message");

        Console.ReadLine();
    }

    private void Compose()
    {
        var catalog = new DirectoryCatalog(@".\");
        var container = new CompositionContainer(catalog);
        container.ComposeParts(this);
    }
}

I'm pretty sure if you do it this way, then MEF will be able to satisfy the import and you'll have yourself a MessageService instance which you can then pass into the ServiceManager.

marc_s
Thanks. I've done something similar in the end whereby I put an Export attribute on my ServiceManager and then Imported it into my Program class.I guess I'm just trying to understand how the containers compose their parts and when. Should the service.core project be loading its own container and using that or should their be just the one container in an application.Having difficulty finding appropriate documentation on the Framework as a whole that tries to explain this.
Apocwhen
Not 100% sure what to tell you - I'm pretty new to this stuff, too :-) But my understanding is: with the container.ComposeParts(this), you tell MEF to resolve all the references in "this" - the "Program" class. This does not extend to the ServiceManager that you create later on (after MEF has composed the parts). Maybe you need to call the ComposeParts on the ServiceManager as well, explicitly - again, not 100% sure....
marc_s
Yes I think that works too. I also came across this earlier post which was describing the same issue I was having above:http://stackoverflow.com/questions/1845892/import-property-always-null-mef-import-issueI think I need to learn more about composition. Thanks again.
Apocwhen