Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Missing dependency" exception with MEF 2

Tags:

.net

mef

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?

like image 297
smwikipedia Avatar asked Sep 04 '14 07:09

smwikipedia


1 Answers

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.

like image 50
smwikipedia Avatar answered Oct 08 '22 18:10

smwikipedia