ImportMany problem: first loaded dll overwrites content of all other dlls in container

Dec 10, 2010 at 2:33 PM
Edited Dec 10, 2010 at 3:16 PM

Hello. I have a problem with ImportMany in my project. As the MEF example "SimpleCalculator3" has the same problem, i'll use it's code to explain the problem.

Calculator uses ImportMany:

 

        [ImportMany]
        IEnumerable<Lazy<IOperation, IOperationData>> operations;

 

and ComposeParts:

        private CompositionContainer _container;

        private Program()
        {
            //An aggregate catalog that combines multiple catalogs
            var catalog = new AggregateCatalog();
            //Adds all the parts found in the same assembly as the Program class
            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
            catalog.Catalogs.Add(new DirectoryCatalog("d:\\Projects\\MEF\\SimpleCalculator\\SimpleCalculator3\\Extensions"));


            //Create the CompositionContainer with the parts in the catalog
            _container = new CompositionContainer(catalog);

            //Fill the imports of this object
            try
            {
                this._container.ComposeParts(this);
            }
            catch (CompositionException compositionException)
            {
                Console.WriteLine(compositionException.ToString());
            }

Original code from the Class1.cs from ExtendedOperations project:

namespace ExtendedOperations {

    [Export(typeof(SimpleCalculator3.IOperation))]
    [ExportMetadata("Symbol", '%')]
    public class Mod : SimpleCalculator3.IOperation
    {
        public int Operate(int left, int right)
        {
            return left % right;
        }
    }

}

Let's change it:

    ...
    [ExportMetadata("Symbol", '*')]
public class Mult: SimpleCalculator3.IOperation
...
            return left * right;
    ...

Now let's compile solution and change dll name from "ExtendedOperations.dll" to "Mult.dll". If we'll run Calculator we will see that calculator can do it's basic operations (addition, subtraction) and also multiplication. Now let's change it once more:

    ...
    [ExportMetadata("Symbol", '/')]
public class Div: SimpleCalculator3.IOperation ... return left / right;
    ...

Let's compile project and change dll's name from "ExtendedOperations.dll" to "Div.dll". Now we have 2 dlls in "Extensions" folder. Let's run Calculator.

And there is the problem: we can add, substract and divide, but we no longer can multiply! That's because after

this._container.ComposeParts(this);

container contains these parts:
0: SimpleCalculator3.Add
1: SimpleCalculator3.Substract
2: ExtendedOperations.Div
and...
3: ExtendedOperations.Div
instead of
3: ExtendedOperations.Mult. 
Container after Importmany contains all dlls, but they all are the copy of the first dll. What can be the solution of this problem? Sorry for my english.
Dec 10, 2010 at 4:27 PM

It seems most likely that you just accidentally recompiled the code both before and after renaming the DLL, resulting in two different assemblies compiled from the same source code.

 

To avoid confusing yourself, stop manually changing source code and renaming DLLs like that. Just put two different library projects in your solution, one with the division operation and one with the multiplication operation.

Dec 10, 2010 at 5:36 PM
Edited Dec 10, 2010 at 5:52 PM

 

Thanks for reply. =) That was just an example and I'm pretty sure that I checked folder condition after I compiled the project and before I ran Calculator. Of course in real situation I used several projects with dlls.

I just did like you said - the problem is still remained.

Dec 10, 2010 at 6:02 PM
Edited Dec 10, 2010 at 6:03 PM

That's my project with the same problem:

Part of main program:

namespace VirtuaLab_Interface
{
    public interface MEFInterface
    {
        String pluginName { get; }
        Bitmap pluginImage { get; }
    }
}

namespace Laboratory
{
    class MEF
    {
        [ImportMany]
        IEnumerable<VirtuaLab_Interface.MEFInterface> plugins;

        private CompositionContainer _container;

        public MEF()
        {
            var catalog = new AggregateCatalog(new DirectoryCatalog("Plugins"));
            _container = new CompositionContainer(catalog);

            try
            {
                this._container.ComposeParts(this);
            }
            catch (CompositionException compositionException)
            {
                MessageBox.Show(compositionException.ToString());
            }
        }
    }
}

Plugin 1 in the same solution:

namespace VirtuaLab_Plugin
{
    [Export(typeof(VirtuaLab_Interface.MEFInterface))]
    [ExportMetadata("PluginID", "test408751641d97ts913yk092yj0d914w2yje8yeh")]
    public class MainTest : VirtuaLab_Interface.MEFInterface
    {
        private String _pluginName = "Test plugin";
        private Bitmap _pluginImage = VirtuaLab_Plugin.Properties.Resources.Image;

        public String pluginName
        {
            get { return _pluginName; }
        }

        public Bitmap pluginImage
        {
            get { return _pluginImage; }
        }
    }
}

 

Plugin 2 in the other solution:

namespace VirtuaLab_Plugin
{
    [Export(typeof(VirtuaLab_Interface.MEFInterface))]
    [ExportMetadata("PluginID", "408751641d97ts913yk092yj0d914w2yje8yeh")]
    public class MainSecond : VirtuaLab_Interface.MEFInterface
    {
        private String _pluginName = "Second plugin";
        private Bitmap _pluginImage = VirtuaLab_Plugin.Properties.Resources.Image;

        public String pluginName
        {
            get { return _pluginName; }
        }

        public Bitmap pluginImage
        {
            get { return _pluginImage; }
        }
    }
}

 

Dec 10, 2010 at 6:31 PM
Edited Dec 12, 2010 at 12:17 PM

wcoenen, I just did like you said one more time but this time I changed "Assembly name" in Properties of the second plugin - and it works! =) Thanks!

Resolution: all assembly names of all plugins must be different.