如何获取代码所在的程序集路径?

时间:2008-09-09 20:12:28

标签: c# .net reflection

有没有办法获取当前代码所在的程序集的路径?我不想要调用程序集的路径,只需要包含代码的路径。

基本上我的单元测试需要读取一些相对于dll的xml测试文件。无论测试dll是从TestDriven.NET,MbUnit GUI还是其他东西运行,我都希望路径始终正确解析。

编辑:人们似乎误解了我的要求。

我的测试库位于

  

C:\项目\ MyApplication的\ daotests \ BIN \调试\ daotests.dll

我希望得到这条道路:

  

C:\项目\ MyApplication的\ daotests \ BIN \调试\

当我从MbUnit Gui运行时,到目前为止,这三个建议都失败了我们:

  • Environment.CurrentDirectory 给出 c:\ Program Files \ MbUnit

  • System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location 给出 C:\ Documents and 设置\乔治\本地 Settings \ Temp \ .... \ DaoTests.dll

  • System.Reflection.Assembly.GetExecutingAssembly().Location 与前一个相同。

31 个答案:

答案 0 :(得分:956)

我已经定义了以下属性,因为我们经常在单元测试中使用它。

public static string AssemblyDirectory
{
    get
    {
        string codeBase = Assembly.GetExecutingAssembly().CodeBase;
        UriBuilder uri = new UriBuilder(codeBase);
        string path = Uri.UnescapeDataString(uri.Path);
        return Path.GetDirectoryName(path);
    }
}

使用NUnit(其中程序集从临时文件夹运行)时,Assembly.Location属性有时会给你一些有趣的结果,所以我更喜欢使用CodeBase来提供URI格式的路径,然后{ {1}}在开头删除UriBuild.UnescapeDataStringFile://将其更改为正常的Windows格式。

答案 1 :(得分:301)

这有帮助吗?

//get the full location of the assembly with DaoTests in it
string fullPath = System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location;

//get the folder that's in
string theDirectory = Path.GetDirectoryName( fullPath );

答案 2 :(得分:295)

这很简单:

var dir = AppDomain.CurrentDomain.BaseDirectory;

答案 3 :(得分:65)

与John的答案相同,但是一种稍微冗长的扩展方法。

public static string GetDirectoryPath(this Assembly assembly)
{
    string filePath = new Uri(assembly.CodeBase).LocalPath;
    return Path.GetDirectoryName(filePath);            
}

现在你可以做到:

var localDir = Assembly.GetExecutingAssembly().GetDirectoryPath();

或者如果您愿意:

var localDir = typeof(DaoTests).Assembly.GetDirectoryPath();

答案 4 :(得分:44)

使用CodeBase和UNC Network共享时,唯一有效的解决方案是:

System.IO.Path.GetDirectoryName(new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);

它也适用于普通的URI。

答案 5 :(得分:31)

这应该有效,除非程序集是阴影复制

string path = System.Reflection.Assembly.GetExecutingAssembly().Location

答案 6 :(得分:14)

这个怎么样:

System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

答案 7 :(得分:11)

我怀疑这里真正的问题是你的测试运行器正在将你的程序集复制到另一个位置。在运行时无法确定程序集的复制位置,但您可以翻转开关以告诉测试运行程序从何处运行程序集,而不是将其复制到影子目录。

当然,每个测试跑步者的这种转换可能会有所不同。

您是否考虑将XML数据作为资源嵌入测试程序集中?

答案 8 :(得分:11)

AppDomain.CurrentDomain.BaseDirectory

适用于MbUnit GUI。

答案 9 :(得分:7)

var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyPath = assembly.GetFiles()[0].Name;
var assemblyDir = System.IO.Path.GetDirectoryName(assemblyPath);

答案 10 :(得分:7)

这个怎么样......

string ThisdllDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

然后只是破解你不需要的东西

答案 11 :(得分:7)

这是John Sibly代码的VB.NET端口。 Visual Basic不区分大小写,因此他的一些变量名称与类型名称冲突。

Public Shared ReadOnly Property AssemblyDirectory() As String
    Get
        Dim codeBase As String = Assembly.GetExecutingAssembly().CodeBase
        Dim uriBuilder As New UriBuilder(codeBase)
        Dim assemblyPath As String = Uri.UnescapeDataString(uriBuilder.Path)
        Return Path.GetDirectoryName(assemblyPath)
    End Get
End Property

答案 12 :(得分:6)

您所在的当前目录。

Environment.CurrentDirectory;  // This is the current directory of your application

如果您使用build复制.xml文件,则应该找到它。

System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(SomeObject));

// The location of the Assembly
assembly.Location;

答案 13 :(得分:6)

tl;博士

程序集和 DLL 文件的概念不同。根据程序集的加载方式,路径信息会丢失或根本不可用。 不过,大多数情况下,所提供的答案都会奏效。


这个问题和之前的答案存在一个误解。在大多数情况下,提供的答案可以正常工作,但是 在某些情况下,不可能获得当前代码所在的程序集的正确路径。

程序集的概念 - 包含可执行代码 - 和 dll 文件 - 包含程序集 - 不是紧密耦合的。一个程序集可能 来自 DLL 文件,但并非必须如此。

使用 Assembly.Load(Byte[]) (MSDN) 方法,您可以直接从内存中的字节数组加载程序集。 字节数组来自哪里并不重要。它可以从文件加载,从互联网下载,动态生成,...

这是一个从字节数组加载程序集的示例。文件加载后路径信息丢失。这是不可能的 获取原始文件路径,之前描述的所有方法都不起作用。

此方法位于执行程序集中,该程序集位于“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();
}

这个类位于 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}");
    }
}

为了完整起见,这里是 GetViaAssemblyCodeBase() 的实现,这对于两个程序集都是相同的:

private static string GetViaAssemblyCodeBase(Assembly assembly)
{
    var codeBase = assembly.CodeBase;
    var uri = new UriBuilder(codeBase);
    return Uri.UnescapeDataString(uri.Path);
}

Runner 打印以下输出:

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\

如您所见,代码库、位置或基目录都不正确。

答案 14 :(得分:6)

这些年来,没有人真正提到这一个。我从令人敬畏的ApprovalTests project中学到了一个技巧。诀窍是您使用程序集中的调试信息来查找原始目录。

这不会在RELEASE模式下工作,也不会在启用优化的情况下工作,也不会在与编译它的机器不同的机器上工作。

但是,这将为您提供相对于您从中调用的源代码文件位置的路径

public static class PathUtilities
{
    public static string GetAdjacentFile(string relativePath)
    {
        return GetDirectoryForCaller(1) + relativePath;
    }
    public static string GetDirectoryForCaller()
    {
        return GetDirectoryForCaller(1);
    }


    public static string GetDirectoryForCaller(int callerStackDepth)
    {
        var stackFrame = new StackTrace(true).GetFrame(callerStackDepth + 1);
        return GetDirectoryForStackFrame(stackFrame);
    }

    public static string GetDirectoryForStackFrame(StackFrame stackFrame)
    {
        return new FileInfo(stackFrame.GetFileName()).Directory.FullName + Path.DirectorySeparatorChar;
    }
}

答案 15 :(得分:6)

据我所知,其他大多数答案都有一些问题。

disk-based (as opposed to web-based), non-GACed assembly执行此操作的正确方法是使用当前正在执行的程序集的CodeBase属性。

这会返回一个网址(file://)。与string manipulationUnescapeDataString混在一起,可以通过利用LocalPath的{​​{1}}属性轻松转换。

Uri

答案 16 :(得分:6)

我一直在使用Assembly.CodeBase而不是Location:

Assembly a;
a = Assembly.GetAssembly(typeof(DaoTests));
string s = a.CodeBase.ToUpper(); // file:///c:/path/name.dll
Assert.AreEqual(true, s.StartsWith("FILE://"), "CodeBase is " + s);
s = s.Substring(7, s.LastIndexOf('/') - 7); // 7 = "file://"
while (s.StartsWith("/")) {
    s = s.Substring(1, s.Length - 1);
}
s = s.Replace("/", "\\");

它一直在工作,但我不再确定它是100%正确的。 http://blogs.msdn.com/suzcook/archive/2003/06/26/assembly-codebase-vs-assembly-location.aspx处的页面显示:

“CodeBase是找到文件的地方的URL,而Location是实际加载文件的路径。例如,如果程序集是从Internet下载的,那么它的CodeBase可能会从“http://”,但其位置可以以“C:\”开头。如果文件是阴影复制的,则位置将是阴影副本目录中文件副本的路径。 知道不保证为GAC中的程序集设置CodeBase也是很好的。但是,将始终为从磁盘加载的程序集设置位置。

可能想要使用CodeBase而不是Location。

答案 17 :(得分:5)

我相信这适用于任何类型的应用程序

AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory

答案 18 :(得分:4)

从.net framework 4.6 / .net core 1.0开始,现在有一个AppContext.BaseDirectory,其结果应与AppDomain.CurrentDomain.BaseDirectory相同,只是AppDomains不属于.net core 1的一部分。 .x /.net标准1.x API。

AppContext.BaseDirectory

答案 19 :(得分:2)

您可以通过以下方式获取bin路径     AppDomain.CurrentDomain.RelativeSearchPath

答案 20 :(得分:2)

当开发人员可以更改代码以包含所需的代码段时,所有建议的答案都有效,但如果您想在不更改任何代码的情况下执行此操作,则可以使用Process Explorer。

它将列出系统上所有正在执行的dll,您可能需要确定正在运行的应用程序的进程ID,但这通常不会太困难。

我已经写了一篇关于如何在II中使用dll的完整描述 - http://nodogmablog.bryanhogan.net/2016/09/locating-and-checking-an-executing-dll-on-a-running-web-server/

答案 21 :(得分:2)

在Windows窗体应用中,您只需使用Application.StartupPath

即可

但对于DLL和控制台应用程序,代码更难记住......

string slash = Path.DirectorySeparatorChar.ToString();
string root = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

root += slash;
string settingsIni = root + "settings.ini"

答案 22 :(得分:1)

如果路径包含“#”符号,则目录将不正确。 因此,我对John Sible答案使用了UriBuilder.Path和UriBuilder.Fragment组合:

public static string AssemblyDirectory
{
    get
    {
        string codeBase = Assembly.GetExecutingAssembly().CodeBase;
        UriBuilder uri = new UriBuilder(codeBase);
        //modification of the John Sibly answer    
        string path = Uri.UnescapeDataString(uri.Path.Replace("/", "\\") + 
          uri.Fragment.Replace("/", "\\"));
        return Path.GetDirectoryName(path);
     }
}

答案 23 :(得分:1)

string path = Path.GetDirectoryName(typeof(DaoTests).Module.FullyQualifiedName);

答案 24 :(得分:0)

这就是我想出的。 在Web项目之间,单元测试(nunit和resharper测试运行器);我发现这对我有用。

我一直在寻找代码来检测构建的配置,Debug/Release/CustomName。唉,#if DEBUG因此,如果有人可以改善

随意编辑和改进。

获取应用文件夹。用于Web根目录,单元测试以获取测试文件的文件夹。

public static string AppPath
{
    get
    {
        DirectoryInfo appPath = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);

        while (appPath.FullName.Contains(@"\bin\", StringComparison.CurrentCultureIgnoreCase)
                || appPath.FullName.EndsWith(@"\bin", StringComparison.CurrentCultureIgnoreCase))
        {
            appPath = appPath.Parent;
        }
        return appPath.FullName;
    }
}

获取bin文件夹:用于使用反射执行程序集。如果由于构建属性而在那里复制文件。

public static string BinPath
{
    get
    {
        string binPath = AppDomain.CurrentDomain.BaseDirectory;

        if (!binPath.Contains(@"\bin\", StringComparison.CurrentCultureIgnoreCase)
            && !binPath.EndsWith(@"\bin", StringComparison.CurrentCultureIgnoreCase))
        {
            binPath = Path.Combine(binPath, "bin");
            //-- Please improve this if there is a better way
            //-- Also note that apps like webapps do not have a debug or release folder. So we would just return bin.
#if DEBUG
            if (Directory.Exists(Path.Combine(binPath, "Debug"))) 
                        binPath = Path.Combine(binPath, "Debug");
#else
            if (Directory.Exists(Path.Combine(binPath, "Release"))) 
                        binPath = Path.Combine(binPath, "Release");
#endif
        }
            return binPath;
    }
}

答案 25 :(得分:0)

这应该有效:

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
Assembly asm = Assembly.GetCallingAssembly();
String path = Path.GetDirectoryName(new Uri(asm.EscapedCodeBase).LocalPath);

string strLog4NetConfigPath = System.IO.Path.Combine(path, "log4net.config");

我使用它来部署DLL文件库以及一些配置文件(这是从DLL文件中使用log4net)。

答案 26 :(得分:0)

我发现我的解决方案足以检索位置。

var executingAssembly = new FileInfo((Assembly.GetExecutingAssembly().Location)).Directory.FullName;

答案 27 :(得分:0)

我过去在NUnit中遇到过相同的行为。默认情况下,NUnit将程序集复制到临时目录中。您可以在NUnit设置中更改此行为:

enter image description here

可能TestDriven.NETMbUnit GUI具有相同的设置。

答案 28 :(得分:0)

对于ASP.Net,它不起作用。我在Why AppDomain.CurrentDomain.BaseDirectory not contains "bin" in asp.net app?找到了一个更好的解决方案。它适用于Win应用程序和ASP.Net Web应用程序。

public string ApplicationPath
    {
        get
        {
            if (String.IsNullOrEmpty(AppDomain.CurrentDomain.RelativeSearchPath))
            {
                return AppDomain.CurrentDomain.BaseDirectory; //exe folder for WinForms, Consoles, Windows Services
            }
            else
            {
                return AppDomain.CurrentDomain.RelativeSearchPath; //bin folder for Web Apps 
            }
        }
    }

答案 29 :(得分:-2)

我用它来获取Bin目录的路径:

var i = Environment.CurrentDirectory.LastIndexOf(@"\");
var path = Environment.CurrentDirectory.Substring(0,i); 

你得到这个结果:

  

“c:\ users \ ricooley \ documents \ visual studio   2010 \项目\ Windows_Test_Project \ Windows_Test_Project \ BIN“

答案 30 :(得分:-3)

网络应用程序?

Server.MapPath("~/MyDir/MyFile.ext")