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

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

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

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

我的测试库位于say

C:\project\myApplication\daotest\bin\Debug\daotests.dll

我想得到这条路:

C:\项目\我的应用程序\道测试\bin\调试\

到目前为止,当我从MbUnit Gui运行时,这三个建议让我失望:

  • Environment.CurrentDirectory返回c:\Program Files\MbUnit

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

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

737358 次浏览

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

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

您所在的当前目录。

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 Assemblyassembly.Location;

这个有用吗?

//get the full location of the assembly with DaoTests in itstring fullPath = System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location;
//get the folder that's instring theDirectory = Path.GetDirectoryName( fullPath );
var assembly = System.Reflection.Assembly.GetExecutingAssembly();var assemblyPath = assembly.GetFiles()[0].Name;var assemblyDir = System.IO.Path.GetDirectoryName(assemblyPath);

我怀疑这里真正的问题是您的测试运行程序正在将您的程序集复制到不同的位置。在运行时没有办法知道程序集是从哪里复制的,但您可能可以翻转一个开关来告诉测试运行程序从它所在的位置运行程序集,而不是将它复制到影子目录。

当然,每个测试运行器的这种切换可能是不同的。

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

这个怎么样:

System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string path = Path.GetDirectoryName(typeof(DaoTests).Module.FullyQualifiedName);

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

Assembly a;a = Assembly.GetAssembly(typeof(DaoTests));string s = a.CodeBase.ToUpper(); // file:///c:/path/name.dllAssert.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,而位置是实际加载文件的路径。例如,如果程序集是从Internet下载的,其CodeBase可能以"超文本传输协议://"开头,但其位置可能以"C:\"开头。如果文件是影子复制的,位置将是影子复制目录中文件副本的路径。也很高兴知道CodeBase不能保证为GAC中的程序集设置。但是,将始终为从磁盘加载的程序集设置位置。"

可能想要使用CodeBase而不是位置。

说明:汇编. CodeBase在. NET Core/. NET 5+:https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.codebase?view=net-5.0中已弃用

原答复:

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

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格式。

这是John Sible代码的VB.NET移植。Visual Basic不区分大小写,所以他的几个变量名与类型名冲突。

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

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

就这么简单:

var dir = AppDomain.CurrentDomain.BaseDirectory;
AppDomain.CurrentDomain.BaseDirectory

使用MbUnit GUI。

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

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

你得到这个结果:

"c:\users\ricooley\documents\visual studio2010\Projects\Windows_Test_Project\Windows_Test_Project\bin"

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

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

它也适用于普通的URI。

这应该工作:

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

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

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

随意编辑和改进。

获取应用文件夹。对Web根很有用,unittest获取测试文件的文件夹。

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 DEBUGif (Directory.Exists(Path.Combine(binPath, "Debug")))binPath = Path.Combine(binPath, "Debug");#elseif (Directory.Exists(Path.Combine(binPath, "Release")))binPath = Path.Combine(binPath, "Release");#endif}return binPath;}}

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

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

这将返回一个URL(file://)。而不是搞乱字符串操作UnescapeDataString,可以通过利用UriLocalPath属性轻松转换。

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

网络应用程序?

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

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

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

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

在此处输入图片描述

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

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

这将无法在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;}}

您可以通过以下方式获取bin路径应用程序域。当前域。相对搜索路径

这个怎么样…

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

那就砍掉你不需要的东西

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

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

我已经为II-http://nodogmablog.bryanhogan.net/2016/09/locating-and-checking-an-executing-dll-on-a-running-web-server/中的dll编写了如何做到这一点的完整描述

在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"

如果路径包含“#”符号,您将获得不正确的目录。所以我使用了John Sible答案的修改,即UriBuilder. Path和UriBuilder. Fra的组合:

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

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

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

从. net Framework 4.6/. net core 1.0开始,现在有一个应用程序上下文。基本目录,它应该给出与AppDomain.CurrentDomain.BaseDirectory相同的结果,除了AppDomain不是. net core 1. x标准1. x API /.net一部分。

AppContext.BaseDirectory

编辑:留档现在甚至状态:

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

事实上,组装位置文档 doc说:

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

对于ASP. Net,它不起作用。我在为什么AppDomain. currency tDomain. BaseDirectory在asp.net应用程序中不包含“bin”?找到了一个更好的覆盖解决方案。它适用于Win Application和ASP. Net Web Application。

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

tl; dr

程序集和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 reflectionassembly?.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.exeGetViaAssemblyLocation:GetViaAppDomain       : D:\Software\DynamicAssemblyLoad\DynamicAssemblyLoad\bin\Debug\Hello from Application:GetViaAssemblyCodeBase: D:/Software/DynamicAssemblyLoad/DynamicAssemblyLoad/bin/Debug/Runner.exeGetViaAssemblyLocation:GetViaAppDomain       : D:\Software\DynamicAssemblyLoad\DynamicAssemblyLoad\bin\Debug\

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