Search code examples
c#mef

MEF Import doesn't work as expected


I have two classes with exports:

[Export(typeof(Mod))]
public class CoreMod : Mod
{
    [ImportingConstructor]
    public CoreMod()
    {
      //here goes my constructor
    }
}

[Export(typeof(Mod))]
public class AnotherMod : Mod
{
    [ImportingConstructor]
    public AnotherMod()
    {
      //here goes my constructor
    }
}

CoreMod is in my main assembly, AnotherMod is in the external assembly. Mod is in yet another assembly, which they are both referencing.
In my app I have a class which tries to load Mods via MEF:

class ModManager
{
    [ImportMany(typeof(Mod))]
    public static IEnumerable<Mod> Mods { get; set; }

    public List<Mod> LoadedMods { get; set; } 

    public ModManager()
    {
        AggregateCatalog catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(CoreMod).Assembly));
        catalog.Catalogs.Add(new DirectoryCatalog(
            Path.GetDirectoryName(
                new Uri(Assembly.GetExecutingAssembly()
                               .CodeBase).LocalPath)));

        var container = new CompositionContainer(catalog);
        container.ComposeParts(this);

        LoadedMods = Mods.ToList();
    }
}

Looks to me like all imports should be satisfied, but it still fails to import anything (Mods is null). What am I doing wrong?


Solution

  • I think what is happening is that you have your CompositionContainer as a function variable instead of a class variable. Also, MEF does not support importing to a static variable. Try using this:

    class ModManager
    {
        [ImportMany(typeof(Mod))]
        public IEnumerable<Mod> Mods { get; set; }
    
        public List<Mod> LoadedMods { get; set; } 
        CompositionContainer _container;
    
        public ModManager()
        {
            AggregateCatalog catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new AssemblyCatalog(typeof(CoreMod).Assembly));
            catalog.Catalogs.Add(new DirectoryCatalog(
                Path.GetDirectoryName(
                    new Uri(Assembly.GetExecutingAssembly()
                                   .CodeBase).LocalPath)));
    
            _container = new CompositionContainer(catalog);
            this._container.ComposeParts(this);
    
            this.LoadedMods = this.Mods.ToList();
        }
    }