877

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

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

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

我的测试库位于说

C:\projects\myapplication\daotests\bin\Debug\daotests.dll

我想得到这条路:

C:\projects\myapplication\daotests\bin\Debug\

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

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

  • System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location 给出C:\Documents and Settings\george\Local Settings\Temp\ ....\DaoTests.dll

  • System.Reflection.Assembly.GetExecutingAssembly().Location 给出与前一个相同的结果。

4

31 回答 31

1136

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

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 格式的路径,然后UriBuild.UnescapeDataString删除File://开头的 ,并将GetDirectoryName其更改为正常的 windows 格式.

于 2008-11-12T13:24:56.133 回答
346

这有帮助吗?

//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 );
于 2008-09-09T21:26:52.093 回答
345

就这么简单:

var dir = AppDomain.CurrentDomain.BaseDirectory;
于 2010-05-22T09:14:20.027 回答
73

与约翰的答案相同,但扩展方法稍微不那么冗长。

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();
于 2010-04-02T14:43:27.357 回答
50

使用 CodeBase 和 UNC 网络共享时唯一对我有用的解决方案是:

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

它也适用于普通的 URI。

于 2012-03-16T12:40:45.580 回答
38

这应该可以工作,除非程序集被影子复制

string path = System.Reflection.Assembly.GetExecutingAssembly().Location
于 2008-09-09T20:14:36.807 回答
22

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

AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory
于 2019-09-22T16:48:33.130 回答
15

那这个呢:

System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
于 2008-09-09T21:40:06.367 回答
14
AppDomain.CurrentDomain.BaseDirectory

与 MbUnit GUI 一起工作。

于 2010-06-16T08:07:46.710 回答
12

我怀疑这里真正的问题是您的测试运行程序正在将您的程序集复制到不同的位置。在运行时无法判断程序集是从哪里复制的,但您可以拨动一个开关来告诉测试运行程序从它所在的位置运行程序集,而不是将其复制到影子目录。

当然,对于每个测试运行者,这样的切换可能会有所不同。

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

于 2008-09-09T21:36:04.270 回答
10

这个怎么样 ...

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

然后砍掉你不需要的东西

于 2016-08-29T22:37:14.957 回答
10

从 .net framework 4.6 / .net core 1.0 开始,现在有一个AppContext.BaseDirectory,它应该给出与 相同的结果AppDomain.CurrentDomain.BaseDirectory,除了 AppDomains 不是 .net core 1.x /.net standard 1.x API 的一部分.

AppContext.BaseDirectory

编辑:文档现在甚至声明:

在 .NET 5.0 及更高版本中,对于捆绑程序集,返回的值是宿主可执行文件的包含目录。

事实上,Assembly.Location doc文档说:

在 .NET 5.0 和更高版本中,对于捆绑的程序集,返回的值是一个空字符串。

于 2020-06-28T17:40:03.307 回答
8

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

对于基于磁盘(相对于基于 Web)、非 GAC 程序集执行此操作的正确方法是使用当前执行程序集的CodeBase属性。

这将返回一个 URL ( file://)。与其搞乱字符串操作or ,UnescapeDataString不如利用LocalPath.Uri

var codeBaseUrl = Assembly.GetExecutingAssembly().CodeBase;
var filePathToCodeBase = new Uri(codeBaseUrl).LocalPath;
var directoryPath = Path.GetDirectoryName(filePathToCodeBase);
于 2014-06-16T18:13:53.053 回答
7
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyPath = assembly.GetFiles()[0].Name;
var assemblyDir = System.IO.Path.GetDirectoryName(assemblyPath);
于 2008-09-09T21:32:28.960 回答
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
于 2009-05-19T18:58:27.997 回答
7

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\

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

于 2021-07-02T10:05:30.993 回答
6

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

这不会在 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;
    }
}
于 2015-09-30T15:27:55.303 回答
5

我一直在使用 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:\”开头。如果文件是卷影复制的,则位置将是卷影复制目录中文件副本的路径。知道 CodeBase 也不能保证为 GAC 中的程序集设置。但是,将始终为从磁盘加载的程序集设置位置。 "

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

于 2008-09-09T21:50:49.523 回答
4

您所在的当前目录。

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;
于 2008-09-09T20:16:04.463 回答
3

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

于 2016-04-22T13:19:47.177 回答
3

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

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

我已经写了关于如何为 II 中的 dll 执行此操作的完整描述 - http://nodogmablog.bryanhogan.net/2016/09/locating-and-checking-an-executing-dll-on-a-running-web -服务器/

于 2016-09-17T16:24:17.927 回答
3

在 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"
于 2017-12-11T19:39:54.537 回答
2

如果路径包含“#”符号,您将获得不正确的目录。因此,我使用了对 John Sibly 答案的修改,即 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);
     }
}
于 2018-10-29T15:12:51.960 回答
2

对于 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 
            }
        }
    }
于 2020-08-28T02:30:54.273 回答
1
string path = Path.GetDirectoryName(typeof(DaoTests).Module.FullyQualifiedName);
于 2008-09-09T21:46:48.783 回答
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)。

于 2013-06-12T08:04:28.510 回答
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;
    }
}
于 2013-07-03T05:20:50.563 回答
0

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

var executingAssembly = new FileInfo((Assembly.GetExecutingAssembly().Location)).Directory.FullName;
于 2015-09-23T11:54:32.190 回答
0

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

在此处输入图像描述

也许TestDriven.NETMbUnitGUI 有相同的设置。

于 2015-09-30T09:55:13.407 回答
-3

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

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

你得到这个结果:

“c:\users\ricooley\documents\visual studio 2010\Projects\Windows_Test_Project\Windows_Test_Project\bin”

于 2011-12-21T18:00:49.467 回答
-3

Web应用程序?

Server.MapPath("~/MyDir/MyFile.ext")
于 2014-06-18T10:34:01.177 回答