tl;dr
The concept of an assembly and a DLL file are not the same. Depending on how the assembly was loaded the path information gets lost or is not available at all.
Most of the time the provided answers will work, though.
There is one misconception the question and the previous answers have. In most of the cases the provided answers will work just fine but
there are cases where it is not possible to get the correct path of the assembly which the current code resides.
The concept of an assembly - which contains executable code - and a dll file - which contains the assembly - are not tightly coupled. An assembly may
come from a DLL file but it does not have to.
Using the Assembly.Load(Byte[])
(MSDN) method you can load an assembly directly from a byte array in memory.
It does not matter where the byte array comes from. It could be loaded from a file, downloaded from the internet, dynamically generated,...
Here is an example which loads an assembly from a byte array. The path information gets lost after the file was loaded. It is not possible to
get the original file path and all previous described methods do not work.
This method is located in the executing assembly which is located at "D:/Software/DynamicAssemblyLoad/DynamicAssemblyLoad/bin/Debug/Runner.exe"
static void Main(string[] args)
{
var fileContent = File.ReadAllBytes(@"C:\Library.dll");
var assembly = Assembly.Load(fileContent);
// Call the method of the library using reflection
assembly
?.GetType("Library.LibraryClass")
?.GetMethod("PrintPath", BindingFlags.Public | BindingFlags.Static)
?.Invoke(null, null);
Console.WriteLine("Hello from Application:");
Console.WriteLine($"GetViaAssemblyCodeBase: {GetViaAssemblyCodeBase(assembly)}");
Console.WriteLine($"GetViaAssemblyLocation: {assembly.Location}");
Console.WriteLine($"GetViaAppDomain : {AppDomain.CurrentDomain.BaseDirectory}");
Console.ReadLine();
}
This class is located in the Library.dll:
public class LibraryClass
{
public static void PrintPath()
{
var assembly = Assembly.GetAssembly(typeof(LibraryClass));
Console.WriteLine("Hello from Library:");
Console.WriteLine($"GetViaAssemblyCodeBase: {GetViaAssemblyCodeBase(assembly)}");
Console.WriteLine($"GetViaAssemblyLocation: {assembly.Location}");
Console.WriteLine($"GetViaAppDomain : {AppDomain.CurrentDomain.BaseDirectory}");
}
}
For the sake of completeness here is the implementations of GetViaAssemblyCodeBase()
which is the same for both assemblies:
private static string GetViaAssemblyCodeBase(Assembly assembly)
{
var codeBase = assembly.CodeBase;
var uri = new UriBuilder(codeBase);
return Uri.UnescapeDataString(uri.Path);
}
The Runner prints the following output:
Hello from Library:
GetViaAssemblyCodeBase: D:/Software/DynamicAssemblyLoad/DynamicAssemblyLoad/bin/Debug/Runner.exe
GetViaAssemblyLocation:
GetViaAppDomain : D:\Software\DynamicAssemblyLoad\DynamicAssemblyLoad\bin\Debug\
Hello from Application:
GetViaAssemblyCodeBase: D:/Software/DynamicAssemblyLoad/DynamicAssemblyLoad/bin/Debug/Runner.exe
GetViaAssemblyLocation:
GetViaAppDomain : D:\Software\DynamicAssemblyLoad\DynamicAssemblyLoad\bin\Debug\
As you can see, neither the code base, location or base directory are correct.
packages
next to the sln file. BUT when you compile and distribute things there is no sln file and no packages directory. During compilation, things that are needed (but not everything) is copied into the bin directory. Your best bet is to use a postbuild script to copy the file you want. – LogographyAppDomain.CurrentDomain.BaseDirectory
is the correct solution, please refer to this comment which offers a better solution. – Dermis