Search code examples
.netmef

"Missing dependency" exception with MEF 2


I am studying MEF 2. Below code throws below exception:

An unhandled exception of type 'System.Composition.Hosting.CompositionFailedException' occurred in System.Composition.TypedParts.dll

Additional information: Missing dependency 'MessageSenders' on 'MEFStudy.Program'.

when calling the SatisfyImports() method. Why?

using System;
using System.Collections.Generic;
using System.Composition;
using System.Composition.Hosting;


using System.Reflection;

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

        [ImportMany]
        private List<IMessageSender> MessageSenders { get; set; }

        public void Run()
        {
            Compose();
            foreach (IMessageSender sender in MessageSenders)
            {
                sender.Send();
            }

        }

        private void Compose()
        {
            CompositionHost host = new ContainerConfiguration().WithAssembly(Assembly.GetExecutingAssembly()).CreateContainer();
            host.SatisfyImports(this);   // <=========== HERE
            host.Dispose();

        }
    }

    public interface IMessageSender
    {
        void Send();
    }

    [Export(typeof(IMessageSender))]
    public class EmailSender1 : IMessageSender
    {
        public void Send()
        {
            Console.WriteLine("EmailSender1");
        }
    }

    [Export(typeof(IMessageSender))]
    public class EmailSender2 : IMessageSender
    {
        public void Send()
        {
            Console.WriteLine("EmailSender2");
        }
    }

}

Update 1

According to here, there are 2 versions of MEF.

  • non-portable one shiped with .NET Framework
  • portable one available on NuGet

The List<IMessageSender> approach works with non-portable one. But not with the portable one. Is this a bug?


Solution

  • I accidentally changed the following code:

    [ImportMany]
    private List<IMessageSender> MessageSenders { get; set; }
    

    to

    [ImportMany]
    private IEnumerable<IMessageSender> MessageSenders { get; set; }
    

    And it solves the problem.

    But still, why? Isn't List<T> an IEnumerable<T> ?

    ADD

    And even stranger, I changed the IEnumerable to IList, it works. Why?

    Possible explanation

    (I'd like to share my explanations to this.)

    The following interface can reproduce exactly the same error.

    interface IMyList<T> : IList<T>
    {
    
    }
    
    [System.Composition.ImportMany] // MEF 2
    private IMyList<IMessageSender> MessageSenders { get; set; }
    

    The following MEF 2 source shows the reason.

    enter image description here

    The Equals() method of 3 SupportedContactTypes returns false with IMyList<>. So in MEF2 will not return valid export for IMyList<>. And MEF 2 allows no default value for property decorated with [ImportMany] attribute. So in the following logic, the dependency missing exception will be thrown.

    enter image description here

    So we can say, ImportMany attribute only support array and the 3 supported generic types.