This may be more of a problem with how you use assemblies than with the MEF solution.
You speak:
The logic in 6 ControllerAdapters is equal.
Is this same DLL copied 6 times to different plugin directories? If so, then this is a problem.
I modeled your approach and conducted some tests to prove what I was thinking. The code is actually the same as yours and reads plugins from subdirectories of the bin / plugin server directory.
A simple test using NUnit to implement a server class library:
[Test] public void Compose() { var server = new Server(); server.Compose(); Console.WriteLine("Plugins found: " + server.FASTAdapters.Count()); Console.WriteLine(); foreach (var adapter in server.FASTAdapters) { Console.WriteLine(adapter.GetType()); Console.WriteLine(adapter.GetType().Assembly.FullName); Console.WriteLine(adapter.GetType().Assembly.CodeBase); Console.WriteLine(); } Assert.Pass(); }
Test results for one plugin in place:
Plugins found: 1
AdapterPlugin.ControllerAdapter
AdapterPlugin, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null
file: /// C: / USERS / GARKIN / DOCUMENTS / VISUAL STUDIO 2012 / PROJECTS / MEFADAPTERS / ADAPTERSERVER / BIN / DEBUG / PLUGINS / ADAPTER1 / ADAPTERPLUGIN.DLL
Test result for two plugins in place using the same collector that was copied to two different plugin directories (maybe your case):
Plugins found: 2
AdapterPlugin.ControllerAdapter
AdapterPlugin, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null
file: /// C: / USERS / GARKIN / DOCUMENTS / VISUAL STUDIO 2012 / PROJECTS / MEFADAPTERS / ADAPTERSERVER / BIN / DEBUG / PLUGINS / ADAPTER1 / ADAPTERPLUGIN.DLL
AdapterPlugin.ControllerAdapter
AdapterPlugin, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null
file: /// C: / USERS / GARKIN / DOCUMENTS / VISUAL STUDIO 2012 / PROJECTS / MEFADAPTERS / ADAPTERSERVER / BIN / DEBUG / PLUGINS / ADAPTER1 / ADAPTERPLUGIN.DLL
You will also get the same result if you give different names for these DLLs, because in essence it is still the same assembly inside.
Now I am adding a third plugin, but this time it is a different assembly of plugins:
Plugins found: 3
AdapterPlugin.ControllerAdapter
AdapterPlugin, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null
file: /// C: / USERS / GARKIN / DOCUMENTS / VISUAL STUDIO 2012 / PROJECTS / MEFADAPTERS / ADAPTERSERVER / BIN / DEBUG / PLUGINS / ADAPTER1 / ADAPTERPLUGIN.DLL
AdapterPlugin.ControllerAdapter
AdapterPlugin, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null
file: /// C: / USERS / GARKIN / DOCUMENTS / VISUAL STUDIO 2012 / PROJECTS / MEFADAPTERS / ADAPTERSERVER / BIN / DEBUG / PLUGINS / ADAPTER1 / ADAPTERPLUGIN.DLL
AdapterPlugin2.ControllerAdapter
AdapterPlugin2, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null
file: /// C: / USERS / GARKIN / DOCUMENTS / VISUAL STUDIO 2012 / PROJECTS / MEFADAPTERS / ADAPTERSERVER / BIN / DEBUG / PLUGINS / ADAPTER3 / ADAPTERPLUGIN2.DLL
A different assembly, of course, was found and identified correctly.
So, it all comes down to how the .NET runtime processes an assembly, which is a complex and well-defined process and works differently for strongly and weakly named assemblies. I recommend this article for a good explanation of the process: Assembly load routines .
In this case, the same process runs behind the scenes when using MEF:
The .NET runtime finds the first weakly connected plug-in assembly and loads it from this location, and MEF performs export processing.
Then, MEF tries to process the next assembly of the plugin that it found using the directory, but the runtime sees the assembly with the metadata already loaded. Thus, it uses the already loaded one to search for exports and finishes creating an instance of the same type again. This does not apply to the second DLL at all.
It is not possible for the same assembly to load more than once using the runtime. What makes sense when you think about it. An assembly is just a bunch of types with their metadata, and after loading the types are available, there is no need to load them again.
This may not be entirely correct, but I hope this helps explain where the problem is, and it should be clear that duplicating a DLL is useless for this purpose.
Now about what you want to achieve. It seems that all you need is just to get several instances of the SAME adapter plugin to use them for different purposes, which has nothing to do with DLL multiplication.
To get multiple adapter instances, you can define multiple imports with RequiredCreationPolicy installed on CreationPolicy.NonShared on your server that MEF will create for you accordingly:
public class Server { [Import(RequiredCreationPolicy = CreationPolicy.NonShared)] public IFASTAdapter FirstAdapter { get; set; } [Import(RequiredCreationPolicy = CreationPolicy.NonShared)] public IFASTAdapter SecondAdapter { get; set; } // Other adapters ... public void Compose() { var catalog = new AggregateCatalog(); var pluginsDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins"); foreach (string d in Directory.GetDirectories(pluginsDir)) { catalog.Catalogs.Add(new DirectoryCatalog(d)); } var container = new CompositionContainer(catalog); container.ComposeParts(this); } }
An appropriate NUnit test to verify that adapters are created and that they are different instances:
[Test] public void Compose_MultipleAdapters_NonShared() { var server = new Server(); server.Compose(); Assert.That(server.FirstAdapter, Is.Not.Null); Assert.That(server.SecondAdapter, Is.Not.Null); Assert.That(server.FirstAdapter, Is.Not.SameAs(server.SecondAdapter)); }
If all of this helps you to some extent, we can also see how you want to configure what and how to create an instance using app.config.