Set Custom Path to Referenced DLL's?

C#DllReferenceDelay Load

C# Problem Overview


I've got a C# project (call it MainProj) which references several other DLL projects. By adding these projects to MainProj's references, it will build them and copy their resulting DLL's to MainProj's working directory.

What I'd like to do is have these referenced DLL's be located in a subdirectory of MainProj's working directory, i.e. MainProj/bin/DLLs, rather than the working directory itself.

I'm not a very experienced C# programmer, but coming from the C++ world, I'm assuming one approach would be to remove the project references and explicitly load the required DLL's by path and filename (i.e. in C++, LoadLibrary). What I'd prefer to do however, if there's a way, would be to set some sort of "reference binary path", so they'd all be auto-copied to this subdir when I build (and then be referenced from there without me needing to explicitly load each). Is such a thing possible?

If not, what's the preferred method in C# to accomplish what I'm after (i.e. something with Assembly.Load / Assembly.LoadFile / Assembly.LoadFrom? Something in AppDomain perhaps, or System.Environment?)

C# Solutions


Solution 1 - C#

From http://www.vcskicks.com/csharp_assembly.php">this page (untested by me):

Somewhere in your program's initialization (before you access any classes from a referenced assembly) do this:

AppDomain.CurrentDomain.AppendPrivatePath(@"bin\DLLs");

Edit: https://devblogs.microsoft.com/dotnet/why-is-appdomain-appendprivatepath-obsolete/">This article says AppendPrivatePath is considered obsolete, but also gives a workaround.

Edit 2: Looks like the easiest and most kosher way to do this is in the app.config file (see https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/probing-element?redirectedfrom=MSDN">here</a>;):

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="bin\DLLs" />
    </assemblyBinding>
  </runtime>
</configuration>

Solution 2 - C#

From Tomek answer at: https://stackoverflow.com/questions/11410940/loading-dlls-from-path-specified-in-setdlldirectory-in-c-sharp

var dllDirectory = @"C:/some/path";
Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";" + dllDirectory)

It works perfectly for me!

Solution 3 - C#

Here is an other way to proceed without using obsolete AppendPrivatePath. It catches a kind of event "associated dll not found" (so it will be called only if the dll is not found in the default directory).

Works for me (.NET 3.5, not tested other versions)

/// <summary>
/// Here is the list of authorized assemblies (DLL files)
/// You HAVE TO specify each of them and call InitializeAssembly()
/// </summary>
private static string[] LOAD_ASSEMBLIES = { "FooBar.dll", "BarFooFoz.dll" };

/// <summary>
/// Call this method at the beginning of the program
/// </summary>
public static void initializeAssembly()
{
	AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs args)
	{
		string assemblyFile = (args.Name.Contains(','))
			? args.Name.Substring(0, args.Name.IndexOf(','))
			: args.Name;
		
		assemblyFile += ".dll";

		// Forbid non handled dll's
		if (!LOAD_ASSEMBLIES.Contains(assemblyFile))
		{
			return null;
		}

		string absoluteFolder = new FileInfo((new System.Uri(Assembly.GetExecutingAssembly().CodeBase)).LocalPath).Directory.FullName;
		string targetPath = Path.Combine(absoluteFolder, assemblyFile);

		try
		{
			return Assembly.LoadFile(targetPath);
		}
		catch (Exception)
		{
			return null;
		}
	};
}

PS: I did not managed to use AppDomainSetup.PrivateBinPath, it is too laborious.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMetal450View Question on Stackoverflow
Solution 1 - C#AaronView Answer on Stackoverflow
Solution 2 - C#Pedro77View Answer on Stackoverflow
Solution 3 - C#56kaView Answer on Stackoverflow