6

I develop a system with plugins, which loads assemblies at runtime. I have a common interface library, which i share between server and its plugins. But, when i perform LoadFrom for plugin folder and try to find all types, which implement common interface IServerModule i get runtime exception:

The type 'ServerCore.IServerModule' exists in both 'ServerCore.dll' and 'ServerCore.dll'

I load plugins like this:

foreach (var dll in dlls)
{
            var assembly = Assembly.LoadFrom(dll);
            var modules = assembly.GetExportedTypes().Where(
                type => (typeof (IServerModule)).IsAssignableFrom(type)
                && !type.IsAbstract &&
                !type.IsGenericTypeDefinition)
                .Select(type => (IServerModule)Activator.CreateInstance(type));
            result.AddRange(modules);
}

How can i deal with this trouble?

I'll be gratefull for any help

Michael
  • 57,169
  • 9
  • 80
  • 125
Alex Voskresenskiy
  • 2,143
  • 2
  • 20
  • 29
  • Have you seen this? http://stackoverflow.com/questions/1057853/the-type-type-exists-in-both-dlls – Halvard Apr 15 '14 at 12:43
  • @Halvard Yes, i do. But i don't have different versions, i have trouble with loadfrom, that loads me similar assembly twice – Alex Voskresenskiy Apr 15 '14 at 12:52
  • Does it load **the same** assembly twice or does it load **a similar** assembly twice? – Halvard Apr 15 '14 at 12:58
  • 1
    Take a look at [this](http://blogs.microsoft.co.il/sasha/2007/03/06/assembly-load-contexts-subtleties/) – Sriram Sakthivel Apr 15 '14 at 12:59
  • @Halvard forgot to mention, it loads similar assembly twice from different place: first it loads it when starts server, and the second cope is located in plugin folder and autoloaded via LoadFrom – Alex Voskresenskiy Apr 15 '14 at 13:02
  • @SriramSakthivel hmm, took a look at paper you provided. Well, i got the idea, but still don't know how to deal with it.. Can you give me advice, please? – Alex Voskresenskiy Apr 15 '14 at 13:15
  • I need more insight of what you're doing to solve this issue, btw I think I used `Assembly.Load(Byte[])` to avoid such issues. If you can provide a sample complete application demonstrating the problem I'd help, otherwise it is hard to guess. Try using `Assembly.Load` – Sriram Sakthivel Apr 15 '14 at 15:14

2 Answers2

3

Inspect the problem DLL and its dependencies. Chances are good that it is pulling in ServerCore.dll from a different version of .NET than your main application.

I recommend you use MEF if you want to do plugins.

Brandon
  • 38,310
  • 8
  • 82
  • 87
  • Nope... All my projects are build with .Net 4.5. I use Simplee Injector after i get instances of plugins. What also can MEF provide me? I always though that MEF is kind of IoC-container, am i right? – Alex Voskresenskiy Apr 15 '14 at 12:55
  • 2
    MEF is specifically for plugins - it does the loading of assemblies and discovery of interface implementations with support for using attributes to configure the plugins. It is worth reading the front page at least. For your specific issue, use ndepend or ILSpy or .NET Reflector to examine your DLL and application and verify the ServiceCore.dll that is being pulled in for each. The error is because the dll is being loaded 2x from different locations. – Brandon Apr 15 '14 at 15:14
  • 1
    @AlexVoskresenskiy common misconception. MEF is NOT IOC. IOC is NOT a plug in tool. For example you should look at the `Lazy` class that comes with MEF. – Aron Apr 15 '14 at 16:29
0

Well, my solution is ugly, but works and i'll go forward for MEF in future (maybe). For now, i added such thing:

if(Path.GetFileNameWithoutExtension(dll)==Assembly.GetCallingAssembly().GetName().Name)
    continue;

Thanks everybody for awesome replies

EDIT: I came up to more elegant solution, here it is:

var frameworkAssemblies =
                from file in new DirectoryInfo(frameworkDirectory).GetFiles()
                where (file.Extension.ToLower() == ".dll" || file.Extension.ToLower() == ".exe")
                && !AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetName().Name).Contains(file.GetFileNameWithoutExtension())
                select Assembly.LoadFrom(file.FullName);
Alex Voskresenskiy
  • 2,143
  • 2
  • 20
  • 29