"Missing dependency" exception with MEF 2
Asked Answered
L

2

8

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?

Lardner answered 4/9, 2014 at 7:50 Comment(0)
L
4

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.

Lardner answered 4/9, 2014 at 8:35 Comment(1)
Though I may have found the root cause. I don't know the rational behind this. I will start a bounty for this.Lardner
C
0

This is getting a little too long for a comment:

My guess is that MEF is intended to be used on interfaces, not concrete classes. So the missing dependency on List, to me, seems like a design choice, MEF is simply missing an export definition for it.

In the case where you expect an IMyList, the same mechanics apply: MEF doesn't have a concrete type associated with that Interface to be instantiated since there is no export defined for it. Even though a List meets all requirements, it needs to be exported explicitly for IMyList. (This is handy for unit-testing, for example, since you just need to change your export to your Mock-objects.)

Columbine answered 16/9, 2014 at 8:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.