App.config runtime probing with wildcard or recursive - c#

I am trying to load dll's via the <probing> element. I have a folder structure that consists of several plugin folders inside of plugins. So I am looking for a way to recursively go through all these plugins folders to find the dll's.
This is my folder structure:
MyApplication
myapp.exe
plugins
fooplugin
foo.dll
barplugin
bar.dll
This is what my App.config looks like, but it doesn't seem to catch the plugins\* part.
<?xml version="1.0" encoding="utf-8">
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="MyApplication;plugins;plugins\*;"/>
</assemblyBinding>
</runtime>
</configuration>
If I would make it like: <probing privatePath="MyApplication;plugins;plugins\fooplugin;"> it will find foo.dll. But I am not certain which plugins will be present.

It's not possible to use a wildcard search when using the probing element. Instead you need to copy your DLLs into a shared folder or specify every folder where they might exist.
If your plugins are being generated by other projects you can set them to build directly to your plugin folder or preferably have a post build task in the MyApplication project that copies the files into your project plugins folder.

You can easily do what you want by handling the AppDomain.CurrentDomain.AssemblyResolve event.
then inside the attached event handler just call:
Assembly assembly = Assembly.LoadFile(path: assemblyPath);
return assembly; // return resolved assembly
The assemblyPath is the absolute path to the DLL your program is trying to grab, and you could get that by scanning your DLL folder at runtime and then grabbing the path that contains the missing DLL name.

Related

Loading dlls from a different directory using "probing"

When compiling a C# project which has external references, the referenced dlls are being copied to the project's output path (next to the exe).
When running the application, it expects to find the dlls next to the exe.
I'm looking for a way to spread my dll files into different directories Dlls for starters). And have the exe look for the dll files in those directories.
Example:
Let's say we have an application called "App" located under C:\App\App.exe, and also it uses a dll file called "App.dll" which is currently also located under C:\App.
I wish to create a new directory called C:\App\Dlls and move the App.dll file to there, while making sure that the App.exe file will know to look for the dll in the new location.
I've searched the internet and found the probing solution. Here's my code (edited "App.config" file):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas=microsoft-com:asm.v1">
<probing privatePath="Dlls" />
</assemblyBinding>
</runtime>
</configuration>
I compiled my application, created the Dlls directory and moved all the dll files to that directory, but the application crashes.
What am I missing?
Found the solution, the file App.exe.config was missing from my base directory. That's why it didn't work. Now everything works smoothly.

Referencing dlls without copying them C#

When we create a new C# project and reference a dll, the dll is copied to the project's output directory when compiling the project.
Is there a way of referencing dll files and not copying them to the project's output directory, and have the executable work with them when it is being run (something like Assemblies if I'm not mistaken)?
I tried accessing the reference dll's properties, and changed the Copy Local to False but it didn't help (probably because that dll is depending on other dlls located in the dll's directory).
Is there any way of doing that?
Actually you can have you assemblies copied to GAC but this is not always an ideal solution.
You have to remember that each assembly copied to the GAC has to be strong named. If your projects uses some NuGet packages it would be a problem to install all those packages into GAC. I believe it is not a purpose of using NuGet either.
Another option would be loading your DLLs from different directory that default bin folder using <codeBase> tag in you configuration:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="MyAssembly2" culture="neutral" publicKeyToken="307041694a995978"/>
<codeBase version="1.0.1524.23149" href="FILE://C:/Myassemblies/MyAssembly2.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
but as I remember it is possible during runtime.
EDIT: Since your problem is that you have to refer SDK, which is under development, I think neither GAC nor codeBase will work. One thing is versioning problem(you have to refer to the specific SDK version), the other is that you should always recompile your tool after new SDK release because some metadata are stored in your assembly, which can be outdated with the new SDK version.

Assembly binding and redirect

I have an EXE that reference a DLL - for this example I'll call it TestDLL.dll.
The EXE is written in C# and the DLL is written in VB .Net.
I created a demo assembly version of the DLL - for example - TestDLL.dll version 1.0.0.0.
I want to compile the EXE with a reference to the demo version DLL (1.0.0.0). Afterwards - I want the EXE to use the same DLL, but the one I'll put in the GAC, of any version.
In order to do that, I set the "Copy Local" property of the DLL's reference to FALSE.
My goal is for example - after compiling, I'll put in the GAC TestDLL.dll with assembly version 2.1.6.0, and the EXE will find it using the assembly redirect binding. For that, I used a config file. I used this link to create it:
http://msdn.microsoft.com/en-us/library/7wd6ex19(v=vs.71).aspx
So my config file looks about like this:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="en-us" />
<!-- Assembly versions can be redirected in application, publisher policy, or machine configuration files. -->
<bindingRedirect oldVersion="1.0.0.0"
newVersion="2.1.6.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
The problem is that after doing all that, I run the EXE and when accessing the dll, I get the famous error:
System.IO.FileNotFoundException: Could not load file or assembly 'TestDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9d8162944bd6fdc7' or one of its dependencies. The system cannot find the file specified.
File name: 'TestDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9d8162944bd6fdc7'
Meaning, the EXE can't find the original DLL I referenced to.
I know that I can just "reference" the GAC or use reflection, but I don't want to - since this EXE is supposed to work only this way.
Does anyone know what's the problem and how to fix it?
Thanks
Make sure that you have set the proper publicKeyToken. In the code you have shown you are using publicKeyToken="32ab4ba45e0a69a1" which is the public key token from the MSDN link. This obviously is not the public key token of your assembly. For this to work you need to have both assemblies (1.0.0.0 and 2.1.6.0) signed with the same key. To extract the public key token you could use the sn.exe tool or looked at the exception stack trace you are getting (it is telling you that publicKeyToken="9d8162944bd6fdc7"):
sn.exe -Tp myassembly.dll
But if the assembly that the executable was compiled against was not signed with the same key this won't work.
Also I see that you have set the culture="en-us" but does your assembly use this culture? You could also try culture="Neutral".
Finally make sure that you have deployed the proper version of the assembly into the GAC.

Changing C# .dll references from absolute to relative

I have compiled my project and some of my project's added .dlls have absolute references. When I try to run my project on another machine, it looks for the .dlls from the original project path.
How can I make the project look for the .dlls using a relative path?
Edit the .csproj file and change the <HintPath> elements from absolute paths to relative paths.
You may also write your handler for resolving assemblies. In the simplest form it may look like this:
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolveHandler;
..
static Assembly AssemblyResolveHandler(object sender, ResolveEventArgs args)
{
string assemblyPath = "yourpath";
return Assembly.LoadFrom(assemblyPath + args.Name);
}
Another option is adding entry in App.config:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="yourpath"/>
</assemblyBinding>
</runtime>

Using reference libraries (dll) stored in a different folder from the main program?

(This might be a obvious question but I wasn't sure what to ask Bing/Google)
In a VS2008 (C# Winforms) project there are numerous third party libraries that are referenced. The project uses 'Copy Local = True' so that the various DLL files end up in the same folder as the compiled application.
To clean things up I would like to modify the program so that the libraries are all under a subfolder.
For example:
C:\MyProgram\ -> main program folder
C:\MyProgram\Libraries -> DLL storage folder
How would I do this?
The best way to do this is to add an app.config file to your solution and setup private probing paths for each of the sub folders. The CLR will then look in these folders when searching for assemblies
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="subFolder1;subFolder2;" />
</assemblyBinding>
</runtime>
</configuration>
Documentation
http://msdn.microsoft.com/en-us/library/823z9h8w(VS.80).aspx

Categories