13

I'm trying to make application with plugins.

I have MainLib.dll, where I made some commnon interface(let it be ICommon) with 1 method. Then, I made 2 .dlls(plugins) which have reference to MainLib.dll and implement the ICommon in some classes. Also, I removed all the references in this .dlls exept System.

Then, I created an application, which monitors folder ".\\Plugins" and loads all .dlls in newDomain, check if the types in .dll implement ICommon (so this application also reference to MainLib.dll). If yes - add the name of .dll in some list.

And now here the problem: before I tried to load plugins - I load MailLib.dll and System to newDomain because all plugins have dependency of this .dlls. They load correct. Then, I start to load plugins, and here I have:

FileNotFoundException, Could not load file or assembly 'PluginWithException, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.) on string Assembly loadedAssembly = domain.Load(Assembly.LoadFrom(asm).FullName);

PluginWithException assembly has only 2 dependency - System and MainLib. Before I tryied to load PluginWithException I checked assemblies in new domain, System and MainLib were loaded to this domain. So I can't see any ploblems with dependency. I read this topic, and tryed the solution with ProxyDomain but the exception is the same.

What I'm doing wrong?

Here the code:

public static List<string> SearchPlugins(string[] names)
{
    AppDomain domain = AppDomain.CreateDomain("tmpDomain");
    domain.Load(Assembly.LoadFrom(@".\MainLib.dll").FullName);
    domain.Load(@"System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
    MessageBox.Show(GetAssembies(domain)); // here I can see that System and MailLib exist in new domain

    List<string> plugins = new List<string>();

    foreach (string asm in names)
    {
        Assembly loadedAssembly = domain.Load(Assembly.LoadFrom(asm).FullName); // here I have exception

        var theClassTypes = from t in loadedAssembly.GetTypes()
                            where t.IsClass &&
                                  (t.GetInterface("ICommonInterface") != null)
                            select t;
        if (theClassTypes.Count() > 0)
        {
            plugins.Add(asm);
        }
    }
    AppDomain.Unload(domain);
    return plugins;
}
Community
  • 1
  • 1
Dima Serdechnyi
  • 707
  • 2
  • 10
  • 19

1 Answers1

2

You may want to tell the domain where to load your assemblies from:

AppDomain domain = AppDomain.CreateDomain("tmpDomain", null, new AppDomainSetup { ApplicationBase = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins") });

However, I don't see why you are loading assemblies in current (default) domain and also the tmpDomain.

meziantou
  • 20,589
  • 7
  • 64
  • 83
YK1
  • 7,327
  • 1
  • 21
  • 28
  • 1
    Thanks, I tried your code, but the exception is the same, in same line. My aim not to load assemblies in default domain because I don't want to keep garbage in application (image if, it will be over 100 plugins), so I can load some plugin, use it, and throw it away from application, when I don't need it. – Dima Serdechnyi May 05 '13 at 10:36
  • 1
    OK - but when you do `Assembly.LoadFrom(asm)` it will load in the current domain. This defeats your purpose. I suggest you have a `PluginLoader` custom class and load that class in the tmpDomain. Then you can write code in that class to load all plugins using `Assembly.LoadFrom` and return you a list of plugin that you want. – YK1 May 05 '13 at 14:10
  • using sysinternals process explorer - you can find what is loaded in what domain at any time. – YK1 May 05 '13 at 14:16