1

I am trying to use MEF (The version that is built in mono) for a simple pluginsystem to extend my application. I followed various tutorials that are running well with Microsofts .NET framework under windows, but (same code) failing under linux(kernel 3.7.3 - gentoo) with mono-2.10.9.

I created an interface, that all Exports (my extensions) have to reference to in an external assembly:

namespace PlugInInterface {

    [InheritedExport]
    public interface IPlugIn {

        void Execute(); 

    }

}

Then I created a Hostapplication (a ConsoleApplication) that also references to the PluginInterface:

namespace Host {

    class MainClass {

        private static PluginHost plugins;

        public static void Main(string[] args) {
            plugins = new PluginHost();
            foreach(IPlugIn plugin in plugins.plugins) {
                plugin.Execute();
            }
        }
    }


    class PluginHost{

        [ImportMany(typeof(IPlugIn))]
        public List<IPlugIn> plugins = new List<IPlugIn>();

        public PluginHost() {
            var catalog = new DirectoryCatalog("PlugIns");
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);   
        }   
    }
}

And one Extension that gets compiled in the "PlugIns" subfolder of the Debug directory, where the host-application is placed:

namespace TestPlugin1 {
    [Export(typeof(IPlugIn))]
    public class TestPlugin1 : IPlugIn {
        public void Execute() {
            Console.WriteLine("Hello, my Name is TestPlugin_Implementation1");
        }
    }
}

The DirectoryCatalog loads the PlugIn's file ("./PlugIns/TestPlugin1.dll") but it does not recognize it as an Export (a "Part") so the plugins list remains empty. It works, if I put the PluginFile in the application's workingdirectory and change the DirectoryList to: var catalog = new DirectoryCatalog("");

If I run the compiled version that has been compiled from the .NET compiler with mono, the PlugIn is loaded twice.

I tried to replace the DirectoryCatalog manually by loading the PlugIn-files with System.Reflection.Assembly.LoadFile(...); and then using AssemblyCatalogs to load all found assemblies:

class PluginHost{

    [ImportMany(typeof(IPlugIn))]
    public List<IPlugIn> plugins = new List<IPlugIn>();

    public PluginHost() {
        List<AssemblyCatalog> catalogs = new List<AssemblyCatalog>();
        foreach(string plfile in Directory.GetFiles("PlugIns", "*.dll", SearchOption.AllDirectories)) {
            catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.LoadFile(plfile)));
        }           
        var container = new CompositionContainer(new AggregateCatalog(catalogs));
        container.ComposeParts(this);   
    }   
}

This works, but the same as with the compiled .NET executable: the PlugIn loads twice.

Is this a bug of mono and it's implementation of MEF, or am I doing something wrong?

leppie
  • 115,091
  • 17
  • 196
  • 297
Markus Ebner
  • 148
  • 9
  • Not sure if this is the issue, but it looks like you're iterating through each of the files and adding a catalog based on that file. So if you are seeing it load twice, do you have two plugins? – Ian Feb 08 '13 at 19:50
  • @lan The Plugin's assembly is only loaded once, but in the _plugins_ List (within the _PluginHost_) it appears twice – Markus Ebner Feb 08 '13 at 20:04
  • Ah ok, does the Mono version not have a DirectoryCatalog? It seemed odd manually iterating through the files. – Ian Feb 08 '13 at 20:09
  • @Ian The _DirectoryCatalog_ was the first thing I tried (codeblock 2) but that did not recognize the Plugin as Export. – Markus Ebner Feb 08 '13 at 20:14

1 Answers1

1

If I run the compiled version that has been compiled from the .NET compiler with mono, the PlugIn is loaded twice.

This happens because although you have IPlugIn decorated with InheritedExportAttribute you also decorate the plugin with the ExportAttribute. The catalog will match both of these and hence export twice. You need just one of the two approaches. Either keep the InheritedExportAttribute and do not decorate any implementation with the ExportAttribute or decorate all implementations with ExportAttribute and remove the InheritedExportAttribute from the interface.

I haven't figured out why DirectoryCatalog cannot load the plugin assembly on Mono. On CLR is works correctly as you mentioned.

Panos Rontogiannis
  • 4,154
  • 1
  • 24
  • 29