Good evening,
I am developing a plugin for an application (also of my own design). I'm having problems when loading the assembly, because it has referenced libraries. This in itself shouldn't be a problem, and I have added what seems to be all the dependancies, but it's still giving me a runtime error: "Could not load file or assembly 'Interop.OpenAPI, Version=1.10.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."
Now, I've copied all the dlls that are in the bin directory of the plugin project to a folder on the main application project and am using Assembly.LoadFile(path) on them all to load them at runtime before calling the method on the plugin. This is where I get the error. If I inspect the assemblies loaded into AppDomain.CurrentDomain, they are all there.
If I try another approach and, instead of loading the plugin at runtime and create a reference to it instead, all the same dlls are copied into the bin folder and the method runs correctly. However, I can't use this approach because the application will be using one of several plugins which will be determined at runtime.
So, what I need to know is how to determine what's missing?
# // load the plugin
# Assembly assembly = Assembly.LoadFile(Program.pluginPath + "\\" + plugin);
#
# // load the dependencies
# // these files have been copied from the plugin's bin folder, into the app's plugin folder
# // so should be everything that is required by the plugin itself
# Assembly.LoadFile(Program.pluginPath + "\\Interop.VBA.dll");
# Assembly.LoadFile(Program.pluginPath + "\\Interop.MSXML2.dll");
# Assembly.LoadFile(Program.pluginPath + "\\Interop.SystemCode_Lib3.dll");
# Assembly.LoadFile(Program.pluginPath + "\\Interop.SystemCode_Lib4.dll");
# Assembly.LoadFile(Program.pluginPath + "\\Interop.OpenAPI.dll");
# Assembly.LoadFile(Program.pluginPath + "\\miclients.common.dll");
#
# ...
#
# object pluginClients = Activator.CreateInstance(pluginType);
# ((IPluginClients)pluginClients).loadConsultantList(); // this is where I get the runtime error
Thanks for your help | | Snowbunny Tuesday, September 15, 2009 6:17 AM | That doesn't make sense, you'd always use Load() to load an assembly that's not in the CurrentDomain. Your AppDomainSetup will only work when "plugins" is a subdirectory of the directory that contains the .exe. You don't need an AppDomainSetup to get that, the <probing> element in the .config file does the same thing. The point is to change ApplicationBase. Use fuslogvw.exe to troubleshoot this. It will show you exactly where it searched for the assemblies.
Hans Passant.- Marked As Answer bynobugzMVP, ModeratorWednesday, September 16, 2009 2:18 PM
-
| | nobugz Wednesday, September 16, 2009 9:44 AM | Are the plug-ins running in a separate AppDomain? Did you check the result of the LoadFile calls? Is the OpenAPI you are loading the same version (1.10)?
Geert van Horrik - CatenaLogic
Visit my blog: http://blog.catenalogic.com
Looking for a way to deploy your updates to all your clients? Try Updater! | | Geert van Horrik Tuesday, September 15, 2009 7:24 AM | Sorry, I should have given more information. The plugins are running in the same AppDomain for now. The OpenAPI is the same version (it's a copy of the same dll). The results of each LoadFile is the correct assembly, and when I do a AppDomain.CurrentDomain.getAssemblies() in the Immediate window when the error is thrown, I can see all the assemblies have indeed been loaded. Thanks for your reply, any ideas? | | Snowbunny Tuesday, September 15, 2009 9:38 AM | This is a common problem with Assembly.LoadFile(), it loads assemblies without a "context". In other words, the CLR loader has no way to know that the dependencies you loaded are in fact suitable to fulfill the dependencies for the plug-in. The only time LoadFile() is suitable is when you intentionally want to re-load an assembly. You should use Load() instead, that also saves you from having to load the dependencies yourself. If the plug-in directory is not on the program's probing path, I'm sure it isn't, you'll need to use the AppDomain.AssemblyResolve event to help the CLR find the assemblies. Note that this is not usually a problem when you actually use a secondary AppDomain. You would give it an AppDomainSetup that makes the plug-in directory its ApplicationBase. It is because you are loading them in the primary AppDomain that you are getting in trouble.
Hans Passant. | | nobugz Tuesday, September 15, 2009 12:34 PM | Thanks, that sounds just like what I need. I'm having difficulty, though, calling Load() on something that's not the CurrentDomain. I've read that this isn't possible, but you suggest that what I've read is wrong! So, here's a summary of what I'm trying to do:
// set the setup info for the new domain so I can point to the plugins folder<br/>
AppDomainSetup setupInfo = new AppDomainSetup();<br/>
setupInfo.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;<br/>
setupInfo.PrivateBinPath = "plugins";<br/>
<br/>
// create the new AppDomain<br/>
AppDomain pluginAppDomain = AppDomain.CreateDomain("Plugins!Plugin1", null, setupInfo);<br/>
<br/>
// load the plugin assembly<br/>
Assembly pluginAssembly = pluginAppDomain.Load("plugins.plugin1");
When I try to do this, however, I get a runtime error "Could not load file or assembly 'plugins.plugin1, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified." The fact that the version number is correct tells me that it *is* finding the assembly, but it's not loading it correctly. This is my first attempt at using AppDomains and I've done lots of searching without any luck. Could you give me a shove in the right direction, please? Thanks for your patience! | | Snowbunny Wednesday, September 16, 2009 9:18 AM | That doesn't make sense, you'd always use Load() to load an assembly that's not in the CurrentDomain. Your AppDomainSetup will only work when "plugins" is a subdirectory of the directory that contains the .exe. You don't need an AppDomainSetup to get that, the <probing> element in the .config file does the same thing. The point is to change ApplicationBase. Use fuslogvw.exe to troubleshoot this. It will show you exactly where it searched for the assemblies.
Hans Passant.- Marked As Answer bynobugzMVP, ModeratorWednesday, September 16, 2009 2:18 PM
-
| | nobugz Wednesday, September 16, 2009 9:44 AM | OK, Thanks for bearing with me! I've created a new project and kept it to just this code:
AppDomainSetup setupInfo = new AppDomainSetup();
setupInfo.ApplicationBase = "E:\\test\\plugins";
AppDomain pluginAppDomain = AppDomain.CreateDomain("Plugins!Plugin1", null, setupInfo);
<br/>
//I've added the full name, because I thought the short name might be causing the problem<br/>
Assembly pluginAssembly = pluginAppDomain.Load("miclients.plugins.plugin1, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null");
The project is at E:\test\testPlugins. The plugins (as you can see from the code above) are in E:\test\plugins When I run, I get the age-old "cannot find the file specified" chestnut. Looking in fuslogvw ( Log Categories = Default ), I see:
*** Assembly Binder Log Entry (16/09/2009 @ 12:21:45) ***
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
Running under executable E:\test\testplugins\bin\Debug\testplugins.vshost.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: User = EXPEE\Fiona
LOG: DisplayName = miclients.plugins.plugin1, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///E:/test/testplugins/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///E:/test/testplugins/bin/Debug/miclients.plugins.plugin1.DLL.
LOG: Attempting download of new URL file:///E:/test/testplugins/bin/Debug/miclients.plugins.plugin1/miclients.plugins.plugin1.DLL.
LOG: Attempting download of new URL file:///E:/test/testplugins/bin/Debug/miclients.plugins.plugin1.EXE.
LOG: Attempting download of new URL file:///E:/test/testplugins/bin/Debug/miclients.plugins.plugin1/miclients.plugins.plugin1.EXE.
LOG: All probing URLs attempted and failed.
And, in Log Categories = Native Image
*** Assembly Binder Log Entry (16/09/2009 @ 12:31:34) ***
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
Running under executable E:\test\testplugins\bin\Debug\testplugins.vshost.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: User = EXPEE\Fiona
LOG: DisplayName = miclients.plugins.plugin1, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///E:/test/testplugins/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = NULL
Calling assembly : (Unknown).
===
LOG: Start binding of native image miclients.plugins.plugin1, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null.
WRN: No matching native image found.
So, it's looking in the wrong place. But why?! GAH! | | Snowbunny Wednesday, September 16, 2009 10:35 AM | At last! Figured it out. Stupid, really. I just neededthe following in my config:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="plugins" /> </assemblyBinding>
And suddenly, it all works....
Duuuuh! - Unmarked As Answer bynobugzMVP, ModeratorWednesday, September 16, 2009 2:18 PM
- Marked As Answer bySnowbunny Wednesday, September 16, 2009 1:54 PM
-
| | Snowbunny Wednesday, September 16, 2009 1:54 PM |
|