.net Runtime doesn't probe plugin folder - c#

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?

Related

Set manully assembly reference

i have this structure
--Loader.exe
--Core.dll
--Plugins/Test.dll
--C:\Program Files\Program\Program.exe
Assembly Test.dll has reference to Core.dll which is fine. When i run Loader.exe it inject Core.dll into another process (Program.exe) and when it does it's trying to load assembly Test.dll. The problem is that Test.dll is looking for reference Core.dll in path C:\Program Files\Program\ instad of path where it was loaded.
Solution: (i'm searching)
I'm simly looking for way how to load reference from execute path instand of another's process path.
Question:
Don't understand if Core.dll loads Assembly which has reference to Core.dll why it can't load from itself ?
The directory from which referenced assemblies are loaded is determined by the configuration of the AppDomain in which your code is running in, specifically, by the AppDomain.BaseDirectory and AppDomain.RelativeSearchPath properties. By default, the assemblies are loaded from the directory which contains your entry point assembly (usually your main EXE application assembly). To customize these paths you need to create a custom AppDomain. Alternatively, you can load the assemblies manually, using Assembly.LoadFile or Assembly.LoadFrom for example.

Add reference of a .NET library residing in Windows System32 folder

I am using a .NET dll file for image operations and have added it in my C# application using "Add reference" in solution explorer and use its classes. There are many applications use that dll so I do not want to place the dll file in an application specific folder like:
C:\Program Files\<Application Name>\ or
C:\Program Files (x86)\<Application Name>\ or
C:\ProgramData\<Application Name>\ or
C:\Users\<Username>\AppData\
And would like to place the dll file in a common folder like C:\Windows\ or C:\Windows\System32 folder or any other folder that is commonly accessible by all applications in Windows.
It works fine when I put the the dll file in the same folder of the calling exe, but when I place it in C:\Windows\System32 directory, the C# code of my application is not able to locate the dll and gives error:
Unable to load DLL: The specified module could not be found.
(Exception from HRESULT: 0x8007007E)
How do I instruct my code to look for the dll in the system32 directory or in any other common directory?
What other common folder can I use for shared dll and libraries?
This is what the Global Assembly Cache is designed for. As listed in the MS documentation here.
Each computer where the common language run-time is installed has a
machine-wide code cache called the global assembly cache. The global
assembly cache stores assemblies specifically designated to be shared
by several applications on the computer.
But there are pitfalls to using it so be aware of MS's own advice:
You should share assemblies by installing them into the global
assembly cache only when you need to. As a general guideline, keep
assembly dependencies private, and locate assemblies in the
application directory unless sharing an assembly is explicitly
required.

Could not load type 'myinterface' from assembly

I have a solution that includes several projects. A few are libs that are building dll's used in my main project in this solution.
My main project builds with output type console application.
This all works fine.
When i change the build output type to a class library (since i want to use this project as a plugin eventually). The project will still build, this time to a dll.
When i use this plugin in an application where i use it as a dll however, it will run up to a certain point where it's trying to load a type defined in an external dll (so NOT built by my solution) and throw the exception:
Could not load type 'externalinterface' from assembly 'externallib, version=3.0.0.0, Culture=neutral, PublicKeyToken=null'.
The dll's are all in the correct folder,etc.
Also worth noting, the plugin is tested in another location than where i built it. The executable still works on this location, the dll/plugin does not. Same amount of dll's in their folders etc.
EDIT: I already used ILSpy (dll inspector) to open the actual dll that is being referenced (so externallib in the errormessage) and checked if 'externalinterface' was present and it is.
EDIT2: RESOLVED! The program that loaded my plugin was loading the same dll that caused the exception. The dll it loaded was of another version than the one i loaded.
Check whether the type externalinterface is present in the referred dll.
You didn't include the details of the exception the application is throwing. However, based on the message you gave, it appears your assembly does not have a strong name. If the application attempting to load your assembly as a plugin does have a strong name, then .NET will require all assemblies loaded by it also have a strong name, so you need to configure your assembly to have a strong name before continuing.
Maybe some supported dll's which is used by the 'externalinterface' is missing in the target machine. In the target machine, check is all the necessary dll's are present in the output folder.
Or blindly copy paste all the dlls in the output folder from the machine where the code is working to the target machine where you have the problem. After this, if the code is working in the target machine, then try to analyze which supporting dll you are missed to copy.

MEF with extra DLLs

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.

MEF Different Assembly Version Loading Issue

I have a bit of a conundrum with MEF.
I have an installer and configuration application shell which uses MEF to load individual installer components. This gives an end user the ability to select from whatever components have been placed into the install distributable.
The first install components which were written to use this used version 11 of SQLServer SMO libraries. Installing against either 2008R2 or 2012 works fine. (lets call this component A)
I have another team migrating code to a new component but that code uses version 10 of the SQLServer SMO, RMO, and SSIS (DTS) libraries. (lets call this component B)
When MEF goes to load component B I get a LoaderExceptionFailure for one of the SQLServer DLLs (Microsoft.SqlServer.Replication). It actually gives a FileNotFoundException (listing the DLL). The DLL exists in the component's directory. It is the correct version 10.
The shell application already has version 11 files in it.
Is there a way I can tell the application context what to do? Is there a way I can tell the component to load any specific libraries it needs?
I want to assume that each component can specify something "Associated.Library, Version=1.0.0.0, publickey=abcdef123456789, culture=none".
The reason the CLR (not MEF) cannot find the assembly is because it is neither in the GAC, not in the places were the current AppDomain is setup to probe for assemblies.
One way to deal with this kind of problem is to add the missing assembly to the GAC.
Another approach is to add the folder containing the missing assembly to the probing paths of your application. If you don't mind deploying these assemblies in the application base folder (the one containing your executable) then do so. Otherwise you can add deploy it in a sub folder of your application base folder and add the folder to the privatePath element of your app.config.
You will find more information on the article: How the Runtime Locates Assemblies.

Categories