Changing C# .dll references from absolute to relative - c#

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>

Related

Is it possible to separate a C# executable and its dependent dlls in different folder and run the application?

I am working on a feasibility task, where it is required to keep a C# - WPF application in a folder and to keep its dependency dlls in a separate folder. Is it possible to do dynamic loading ?
When I investigated I found that .NET assemblies should be placed in a common directory/sub directories due to security reasons, otherwise it wont work. My requirement is to separate them in a different drive-folder.
Can you suggest a solution for this?
Yes it is possible according https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/probing-element?redirectedfrom=MSDN. You will have to update your configuration file (app.config which gets copied to your.exe.config) with something like this:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin;bin2\subbin;bin3"/>
</assemblyBinding>
</runtime>
</configuration>

Dependent Assembly loading via configuration

I have a visual studio project with is running absolutely fine.
But a new client requirement comes up for deployment for placing the different dlls in different folders.
We have a framework dll which can be used in a different project. There are some third-party dlls on which this framework dll depends upon. So when I use this dll from my project every dependent dll is copied to my local on the build as CopyLocal property is true.
But now with new requirement we can not have CopyLocal property set as True. The client wants no local copy of any dll, rather he wants framework related dll in some location. When I am doing this the dependent DLL's are not getting loded.
I know I have two options:
I can put them in GAC, but I don't want to do this as I want them to support xcopy.
Using reflection(But I am not sure of this that is this the right approach)
Can we do anything using configurations??
You can configure assembly probing paths using the <probing> configuration element:
Specifies application base subdirectories for the common language runtime to search when loading assemblies.
Example from MSDN:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin;bin2\subbin;bin3"/>
</assemblyBinding>
</runtime>
</configuration>
However, if the assemblies in question reside outside the application base ("which is the root location where the application is being executed"), you have the <codeBase> configuration element:
Specifies where the common language runtime can find an assembly.
Example from MSDN:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="neutral" />
<codeBase version="2.0.0.0"
href="http://www.litwareinc.com/myAssembly.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
For the exact details of how the runtime locates assemblies you can refer to this MSDN article.
As OP pointed out, unfortunately codeBase element is a usable option for strong named assemblies only. For private assemblies you need a workaround. Some viable ideas can be found in this discussion such as:
file system links (NTFS junction point) + probing element or AppDomainSetup.PrivateBinPath
AppDomain.CurrentDomain.AssemblyResolve event
I've tested the latter and can confirm it works:
AppDomain.CurrentDomain.AssemblyResolve += (s, e) =>
Assembly.LoadFile(Path.Combine(Settings.Default.AssemblyPath, Path.ChangeExtension(e.Name.Substring(0, e.Name.IndexOf(',')), ".dll")));

App.config runtime probing with wildcard or recursive

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.

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.

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