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


780

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

基本上,我的单​​元测试需要读取一些相对于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 给出与先前相同的结果。


102
这是您的解决方案:var dir = AppDomain.CurrentDomain.BaseDirectory;
贾拉勒·谢尔

7
这应该是公认的解决方案。AppDomain.CurrentDomain.BaseDirectory是正确的方法。
aBetterGamer 2013年


2
我是来这里寻找nuget包的解决方案的,以从其pacakge目录中读取JSON文件。似乎在执行nuget软件包时,“ AppDomain.CurrentDomain.BaseDirectory”指向正在运行的项目目录,而不是nuget软件包目录。这些似乎都没有正确地针对nuget软件包目录。
卢卡斯

@Lucas不,不是因为这不是这个问题的意思(实际上,当被问到这个问题时,nuget不存在)-随时提出一个新问题,然后在那儿ping我,但我现在可以告诉你在大多数情况下是不可能的。对于大多数项目,nuget目录位于packagessln文件旁边。但是,当您编译和分发内容时,没有sln文件,也没有程序包目录。在编译期间,需要的内容(但不是全部)被复制到bin目录中。最好的选择是使用后期构建脚本来复制所需的文件。
乔治·莫尔

Answers:


1035

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

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);
    }
}

Assembly.Location使用NUnit时,该属性有时会给您一些有趣的结果(其中程序集从一个临时文件夹运行),因此我更喜欢使用CodeBaseURI以URI格式为您提供路径,然后UriBuild.UnescapeDataString删除File://开头的内容,并将其GetDirectoryName更改为正常的Windows格式。 。


29
我遇到了一个问题,如果您的目录名称是:c:\ My%20Directory,那么Uri.UnescapeDataString将返回:c:\ My Directory这意味着File.Exists(“ c:\ My Directory \ MyFile.txt ”)将返回false,因为正确的路径实际上是“ c:\ My%20Directory \ MyFile.txt”,因为我们的SVN路径中有空格,当我们将其检出时,它会对空格进行编码。
ROW1

5
使用此方法检查File.Exist()时要小心,因为此方法将在UNC路径上返回false。请改用@Keith的答案。
AZ。

3
不知道您可以将静态信息公开发布。很高兴知道,我认为我更喜欢可读性
Valamas

5
注意:这不适用于网络位置(例如\\ REMOT_EPC \ Folder)
Muxa 2014年

5
如果目录中带有数字符号“#”,这也将不起作用。Windows中目录和文件名中允许使用数字符号。
Huemac 2014年

321

这有帮助吗?

//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 );

看到我的编辑(不是),这对MbUnit的工作方式有些奇怪吗?
乔治·莫尔

3
将xml文件设置为内​​容,与dll复制或从dll读取资源。
基思

22
或者只是typeof(DaoTests).Assembly
拍击

4
@SLaks @JohnySkovdal @Keith:大家好,使用Assembly.GetExecutingAssembly()。它“获取包含当前正在执行的代码的程序集”(来自方法描述)。我在AddIn“ EntitiesToDTOs ”中使用它。有关实际示例,请参见AssemblyHelper.cs
kzfabi 2012年

4
@John Silby的帖子有问题,因为它似乎不适用于UNC路径...例如\\ Server \ Folder \ File.ext。这是一招。+1
蓝莓

312

就这么简单:

var dir = AppDomain.CurrentDomain.BaseDirectory;

11
这应该是公认的解决方案。AppDomain.CurrentDomain.BaseDirectory是正确的方法。
aBetterGamer 2013年

5
感谢您再次关注此问题-不确定在我提出问题时是否可以使用,但现在就可以了。
George Mauer 2013年

120
不,这是错误的。这将返回原始入口点的路径,而不是当前正在执行的代码。如果您从其他路径手动加载了某个程序集,或者从GAC加载了该程序集,它将返回错误的结果。这个答案是正确的:stackoverflow.com/a/283917/243557更快仍然是 Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
nathanchere

9
实际上,这在Web应用程序中不起作用,但据我发现,以下增强功能应适用于任何类型的应用程序:AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory
Ilya Chernomordik

4
如果您只想获取测试程序集的原始bin路径(例如,在子文件夹中获取辅助数据文件),则这对于单元测试非常有用。测试程序集是代码的入口点。
MarioDS '16

68

与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();

6
您是assembly不是要意思Assembly.GetExecutingAssembly()
Dude Pascalou 2014年

3
正如Dude指出的那样,您传入了一个参数,但未能使用它。
克里斯·莫斯基尼

4
对于眼前的问题,这个答案是完全错误的。该答案的修改版本可以为您提供给定程序集的路径。但是,在这里,我们专门在寻找执行程序集,因此传递程序集毫无意义。扩展方法是这项工作的错误工具。
爱德华·布雷

46

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

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

它也适用于普通URI。


5
这应该是公认的答案。真令人讨厌的是,默认代码库无法正确处理UNC共享。
丹尼尔·吉尔伯特

当文件夹包含空格并且上帝知道其他字符时,它崩溃了
MarioDS '17

1
我已经使用了很多,并发现了一种失败的情况:如果这行代码本身是NuGet包的一部分,然后该包将被应用程序使用!我们也可以通过替换GetExecutingAssembly()为来支持这种情况GetCallingAssembly()
Timo

@Timo:您是否已验证此更改是否有副作用?如果是这样,请编辑答案以包含此修复程序。
Ignacio Soler Garcia

@IgnacioSolerGarcia遗憾的是,我必须报告说它只能深入一层,即如果NuGet包被另一个NuGet包调用,它将失败!我现在正在使用它(来自Chernomordik在此页面上的评论):AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory。第一部分用于Web应用程序,第二部分用于其他应用程序。
Timo

32

这应该可行,除非程序集是影子复制的

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

14

那这个呢:

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

11

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

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

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


+1指出卷影复制的问题。但是,确实有可能从中确定原始位置Assembly.CodeBase
tm1

11
AppDomain.CurrentDomain.BaseDirectory

与MbUnit GUI一起使用。


这对于在asp.net网络应用中写入相对于根目录的文件非常有效
Philip Pittle 2014年

我发现这通常效果最好。如果不确定,请选择它。
Erik Bergstedt'2

10

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

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

1
我的实验表明,这是最简单的答案,不仅涵盖Web和控制台应用程序,而且涵盖单元测试和NuGet程序包的调用(嵌套到任何递归级别)。
Timo

8

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

对于基于磁盘(而不是基于Web的),非GACed程序集,执行此操作的正确方法是使用当前正在执行的程序集的CodeBase属性。

这将返回一个URL(file://)。相反瞎搞与字符串操作或者UnescapeDataString,这可以通过利用转换以最小做文章LocalPath的财产Uri

var codeBaseUrl = Assembly.GetExecutingAssembly().CodeBase;
var filePathToCodeBase = new Uri(codeBaseUrl).LocalPath;
var directoryPath = Path.GetDirectoryName(filePathToCodeBase);

1
如果路径包含#EscapedCodeBase工作,则不起作用,但如果路径包含例如%20逐字记录(这是Windows路径中允许的字符序列),则EscapedCodeBase不起作用
Martin Ba

如果我们希望将此代码包含在NuGet包中,可以通过替换GetExecutingAssembly()为来解决该情况GetCallingAssembly()
Timo

8

这个怎么样 ...

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

然后就砍掉不需要的东西


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

7

这是John Sible的代码的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

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;
    }
}

5

您所在的当前目录。

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

如果将.xml文件复制到build中,则应该找到它。

要么

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

// The location of the Assembly
assembly.Location;

如果程序集已被阴影复制,这将是有问题的。
支出者2014年

+1520!Environment.CurrentDirectory如果您在MSBuild任务类中使用反射,则可以工作,其中执行程序集位于GAC中,而您的代码在其他地方。
vulcan raven 2014年

4
通常,CurrentDirectory不会告诉您可执行文件所在的位置。那不是它的用途。它恰好经常位于可执行文件所在的位置,因此许多程序员不了解它们之间的区别。然后,它们最终给期望应用程序了解CurrentDirectory正确使用的某些最终用户带来麻烦。
Bent Tranberg '16

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。


1
@Kiquenet:太多的代码仅用于将URI转换为路径。当然可以改善。查看Mike Schall或SoMoS的答案。您不应尝试在字符串级别转换URI,而应使用合适的对象。好的,Assembly.CodeBase返回字符串而不是更合适的对象(如URI或FileInfo)也很笨拙。
2014年

2

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


2

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

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

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


请注意,首先,本文中的代码是以IIS为中心的,其次,它为您(我相信)提供了所有当前加载的 dll,而不是任何时间运行的dll。
乔治·莫尔

给出的示例与iis有关,但是如果dll在iis之外的进程中运行,则适用相同的步骤。只需确定进程ID即可。我将更新文章以指出这一点。谢谢你的建议。
布赖恩

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"

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

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);
     }
}

0

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

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

随时进行编辑和改进。

正在获取应用程序文件夹。对于Web根目录很有用,unittests用于获取测试文件的文件夹。

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;
    }
}

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)。


fileMap在这里做什么用?
George Mauer 2013年

0

我发现我的解决方案适合于该位置的检索。

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

这已经是评分最高的答案之一,并且在问题中明确提到在这种情况下不起作用。
George Mauer 2015年

抱歉,一定不能错过!显然,我没有彻底阅读。
Tez Wingfield 2015年

0

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

在此处输入图片说明

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


-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”


6
我看不出有避免使用Path.getDirectoryName的理由
Max Keller

@MaxKeller如果看不到原因,并不表示它是正确的。Path.GetDirectoryName的这种替代方法快十倍。
Ruslan Veselov

-3

Web应用程序?

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

2
@christiandev,这是一个答案,但似乎似乎是对错误问题的答案。从这个问题可以很清楚地看出,这不是Web应用程序,而是使用MbUnit运行的程序集。话虽这么说,由于Asp.Net卷影复制,答案仍然不是真的正确(尽管可以想像的是有人问这个问题)。
George Mauer 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.