MEF with extra DLLs - c#

I have an Outlook plugin created that uses MEF to load extensions. The extensions are all created as C# class libraries. When the Outlook plugin starts, it copies all the plugin DLLs from a network directory to the local computer and then loads them via MEF.
For one of them, I'm using the MySql.Data.dll library. That dll is copied to the same directory where I place the DLL's which MEF loads in, but that one isn't working. The end user gets an exception saying it can't find that MySql dll.
What's the trick to placing extra DLLs that are needed by a class library included via an MEF import?

I haven't used MEF in a project but I have had to roll my own plug-in architecture on a couple of occassions. Something you can try is hooking in to the AppDomain.AssemblyResolve event. I don't know how useful the example is on that page but you could examine the assembly name in the event args and attempt to load that assembly from the same folder you are loading the plug-ins from.

Related

.net Runtime doesn't probe plugin folder

We have a .net plugin for an application that does not load a dependent library from the plugin folder.
Scenario:
Application (Revit.exe in program files) -> Loads plugin from c:\programdata\revit\plugindir\ourplugindir\<plugin.dll+dependencies>
On most machines, the load works fine. For the context of the issue, the dll dependencies are as follows
Revit.exe loads plugin.dll (revit.exe is in programfiles, plugins are in a separate predefined directory under programdata)
plugin.dll loads IdentityModel.dll (in ourplugindir directory)
IdentityModel.dll loads System.Text.Encodings.Web.DLL (in ourplugindir)
Successful probing looks like this:
IdentityModel requires System.Text.Encodings.Web.DLL
Initiate probing
Check GAC (fail)
Check root folder where Revit.exe is present (fail)
Check private sub folders where Revit.ext is present (fail)
Check ourplugindir (success)
On the machine where the plugin load fails, for some reason it does not probe ourplugindir and is hence unable to find System.Text.Encodings.Web.DLL.
The plugin dll is built using .net 4.7. The dependency is an indirect dependency.
From MSDN: https://learn.microsoft.com/en-us/dotnet/framework/deployment/how-the-runtime-locates-assemblies
Assembly location can also be determined using the current binding
context. This most often occurs when the Assembly.LoadFrom method is
used and in COM interop scenarios. If an assembly uses the LoadFrom
method to reference another assembly, the calling assembly's location
is considered to be a hint about where to find the referenced
assembly.
Since the plugins are dynamically loaded by Revit.exe, I can only assume that the application uses Assembly.LoadFrom or something similar to load the plugins.
So the question is, why does the runtime correctly probe and find the dependent dll in the plugin folder on some machines while it doesn't probe the same folder on other machines?
Have you tried using an assembly resolver?

Plugin architecture in C# with external dll like Open.XML from Nuget

I have created a plugin architecture in C# app. In special folder I upload dlls and system search for certain interface and using reflection invokes function within plugin. But one of plugins (dlls) references to Open.XML dll which is not installed on the server where app is running. Is it a way to create a plugin ( compile it ?) that contains all libraries that it needs. Or it should be done in a different way?
1) Distribute any required DLLs together with the plugin DLL, and put them inside the plugin folder. Either add the plugin folder to the probing path for assemblies in the app.config, or add a handler for the AssemblyResolve event.
2) Use ILMerge to combine the plugin and required assemblies into one assembly.
If you load all plugins into the same app domain, this will cause funny issues if the same types are merged into multiple plugins.

Assembly or file not found on plugin system C#

I have a project that uses plugins based on an interface, they are coded in other "Class Library" projects in the same main project solution. The main project has a folder that contains all the plugins in dll format. So for example I have a Plugins folder in "Bin/Debug/". All the plugins are compiled on that directory.
Each plugin project has a reference to the main project as it uses the main framework (reference not copied locally).
Each plugin should be able to use methods from other plugins, here I have the problem.
Example:
I have PluginA and PluginB, 2 DLLs, 2 different projects but the DLLs are in the same Plugins folder.
Now I want to instantiate PluginB in PluginA class so I add a reference to PluginB DLL (not copied locally). No errors from the Compiler.
But when I istantiate PluginA on the main project after loading all the plugins assemblies, I get a System.IO.FileNotFoundException Assembly or file not found. (referred to PluginB)
Basically seems that when I call a Plugin, from the main project, that calls another Plugin, I get an error. I've also tried to use the Assembly Resolve event without success.
Maybe I made some mistakes with the entire plugins system, it's the first time I use them.
Sorry for my english, I'm italian.
Thanks for the help.

How to choose a specific version of a DLL at runtime

This is a follow-up to a previous question Is it possible to switch DLLs at runtime so as to use a different version?.
Since posting that question I have reorganised my project but am still have DLL loading problems.
I have 3 main projects: the application, a library containing MEF plugins and a second library containing more MEF plugins. Each plugin handles a type of IO device.
The manufacturer of one of the devices has produced a new set of identically named but incompatible DLLs. I now have 2 plugins to handle each version and put them in 2 separate projects (MEF Lib1 & MEF Lib2).
The MEF loader decides which one of the conflicting plugins to load (only one is needed) and the plugin is told to initialise itself. It then copies its' DLLs (managed and unmanaged) to the execution folder before the DLLs are accessed.
This does not work as desired. The managed DLLs are correct but the unmanaged DLL that actually gets loaded is an older version.
I have tried using the AppDomain.AssemblyResolve event but this only seems to be activated when a DLL cannot be found. In my case, the DLL is always found - just not the one I want.
What am I doing wrong?

Loading C# DLL to C++/CLI - dependencies directory

I wrote a dll c++/cli library which uses my other c# dll library. C++/cli library works fine when I've got c# dll in the same folder as application which calls it. This library will be finally loaded to many applications and a C# dll must not be copied into directory with application. It has to be in the same folder as c++/cli library, but in that cases I've got System.IO.FileNotFoundException.
My suggestion is to load c# library manually or to change path where f.ex. firefox is looking for dependencies, but I tried with LoadLibrary() and Assembly::LoadFrom() methods to force loading from right directory. Of course I added directory path with dll to system PATH.
I work on VS2010.
You don't change the default directory where an application will look for dlls.
At design time put your dll in some well know location, the one you are going to deploy to. Add a reference to it, make sure it's set to Don't copy ever, otherwise it will end up in the bin folder. You have to do this otherwise it won't compile.
When you deploy, you'll need one package to deploy common dlls, and one for each application. Careful you don't create your own version of dll hell, if appA needs an older or new version of the common dll, compared to AppB
Add an AppDomain.AssemblyResolve event to main (for windows app). At run time the event handler will get fired when you reference a type in your dll, and the assembly has not yet been loaded.
In there you load it from the well known location. That usually in config, or in a relative path.
E.g.
AllMyApps
CommonDLLS
MyFirstApp
So the path you load the required common dll from would be "..\CommonDlls\MyCommondll.dll".
NB you will want to secure the dlls in some way, otherwise a bad guy might be able to inject their version of one in to your app, which would be bad...
You can use this mechanism to get the dll from a remote server or a database blob as well.
The simplest case is only a few lines of code, just look the event up. Took me about 15 minutes to get this going in a similar scenario.
Not on this machine though, otherwise I'd have pasted in the code.

Categories