Есть ли способ получить путь для сборки, в которой находится текущий код? Мне не нужен путь вызывающей сборки, только тот, который содержит код.
В принципе, мой unit test должен читать некоторые тестовые файлы xml, которые расположены относительно dll. Я хочу, чтобы путь всегда корректно решался независимо от того, запускается ли тестовая dll из TestDriven.NET, GUI MbUnit или чего-то еще.
Изменить. Люди, похоже, неправильно понимают, что я прошу.
Моя тестовая библиотека находится в разделе
C:\Проекты\MyApplication\daotests\Bin\Debug\daotests.dll
и я хотел бы получить этот путь:
C:\Проекты\MyApplication\daotests\Bin\Debug\
Три предложения до сих пор не сработают, когда я бегу от MbUnit Gui:
Environment.CurrentDirectory
дает c:\Program Files\MbUnit
System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location
дает C:\Documents and
Настройки\джордж\Local
Настройки \Temp \....\DaoTests.dll
System.Reflection.Assembly.GetExecutingAssembly().Location
дает то же самое, что и предыдущее.
Я определил следующее свойство, поскольку это часто используется при модульном тестировании.
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 (где сборки запускаются из временной папки), поэтому я предпочитаю использовать CodeBase
, который дает вам путь в формате URI, затем UriBuild.UnescapeDataString
удаляет File://
в начале и GetDirectoryName
изменяет его на обычный формат Windows.
Помогает ли это?
//get the full location of the assembly with DaoTests in it
string fullPath = System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location;
//get the folder that in
string theDirectory = Path.GetDirectoryName( fullPath );
Это так просто:
var dir = AppDomain.CurrentDomain.BaseDirectory;
То же, что и ответ Джона, но немного менее подробный метод расширения.
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();
assembly
вместо Assembly.GetExecutingAssembly()
?
Единственное решение, которое работало для меня при использовании общих ресурсов CodeBase и UNC Network:
System.IO.Path.GetDirectoryName(new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);
Он также работает с обычными URI.
Это должно работать, если сборка не скопирована теневой копией:
string path = System.Reflection.Assembly.GetExecutingAssembly().Location
Как насчет этого:
System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
Я подозреваю, что настоящая проблема заключается в том, что ваш тестовый бегун копирует вашу сборку в другое место. Во время выполнения нет возможности указать, откуда была скопирована сборка, но вы, вероятно, можете переключить переключатель, чтобы сообщить тестовому бегуну, что он запускает сборку, где он есть, и не копировать его в теневой каталог.
Такой переключатель, вероятно, будет отличаться для каждого тестируемого, конечно.
Рассматривали ли вы возможность встраивания ваших XML-данных в ресурсы в тестовую сборку?
Assembly.CodeBase
.
AppDomain.CurrentDomain.BaseDirectory
работает с GUI MbUnit.
Вот порт 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
Я использовал 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 - это путь, на котором он был загружен. Например, если сборка была загружена из Интернета, ее CodeBase может начинаться с" http:// ", но его местоположение может начинаться с" C:\". Если файл был скопирован с тэпом, то Location будет путь к копии файла в директории shadow copy. Также хорошо знать, что CodeBase не гарантируется для сборок в GAC. Однако расположение всегда будет установлено для сборок, загруженных с диска.
Возможно, вы захотите использовать CodeBase вместо Location.
За все эти годы никто не упомянул об этом. Трюк, который я узнал из удивительного проекта ApprovedTests. Фокус в том, что вы используете информацию об отладке в сборке, чтобы найти исходный каталог.
Это не будет работать в режиме 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;
}
}
Насколько я могу судить, большинство других ответов имеют несколько проблем.
Правильный способ сделать это для дисковой (в отличие от веб-) сборки, отличной от GACed, использовать выполняемое в настоящее время свойство сборки CodeBase
.
Возвращает URL-адрес (file://
). Вместо того, чтобы возиться с строковыми манипуляциями или UnescapeDataString
, это можно преобразовать с минимальной суетой, используя LocalPath
свойство Uri
.
var codeBaseUrl = Assembly.GetExecutingAssembly().CodeBase;
var filePathToCodeBase = new Uri(codeBaseUrl).LocalPath;
var directoryPath = Path.GetDirectoryName(filePathToCodeBase);
#
( EscapedCodeBase
работает, но EscapedCodeBase не работает, если путь содержит, например, %20
дословно (что является допустимой последовательностью символов в пути Windows)
Текущий каталог, в котором вы находитесь.
Environment.CurrentDirectory; // This is the current directory of your application
Если вы скопируете файл .xml со сборкой, вы должны его найти.
или
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(SomeObject));
// The location of the Assembly
assembly.Location;
Environment.CurrentDirectory
работает, если вы используете отражение в классе задач MSBuild, где исполняемая сборка находится в GAC, а ваш код находится где-то еще.
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyPath = assembly.GetFiles()[0].Name;
var assemblyDir = System.IO.Path.GetDirectoryName(assemblyPath);
Как насчет этого...
string ThisdllDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
Затем просто взломайте то, что вам не нужно
Вы можете получить путь к bin AppDomain.CurrentDomain.RelativeSearchPath
string path = Path.GetDirectoryName(typeof(DaoTests).Module.FullyQualifiedName);
Все предлагаемые ответы работают, когда разработчик может изменить код, чтобы включить требуемый фрагмент, но если вы хотите сделать это без изменения кода, вы можете использовать Process Explorer.
Он отобразит все исполняемые DLL в системе, вам может потребоваться определить идентификатор процесса для вашего запущенного приложения, но это обычно не так сложно.
Я написал полное описание того, как это сделать для dll внутри II - http://nodogmablog.bryanhogan.net/2016/09/locating-and-checking-an-executing-dll-on-a-running-web-server/
В прошлом я имел такое же поведение в NUnit
. По умолчанию NUnit
копирует вашу сборку в каталог temp. Вы можете изменить это поведение в настройках NUnit
:
Возможно, TestDriven.NET
и MbUnit
GUI имеют одинаковые настройки.
Я нахожу свое решение подходящим для поиска местоположения.
var executingAssembly = new FileInfo((Assembly.GetExecutingAssembly().Location)).Directory.FullName;
Вот что я придумал. Между веб-проектами, модульные тесты (nunit и resharper test runner); Я нашел, что это сработало для меня.
Я искал код для определения конфигурации, в которой находится сборка, Debug/Release/CustomName
. Увы, #if DEBUG
. Поэтому, если кто-то может улучшить это!
Не стесняйтесь редактировать и улучшать.
Получение папки приложения. Полезно для веб-корней, 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;
}
}
Это должно работать:
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 вместе с некоторым конфигурационным файлом (это нужно использовать log4net из DLL файла).
fileMap
используется fileMap
?
Я использую это, чтобы получить путь к Bin Directory:
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"
Веб-приложение?
Server.MapPath("~/MyDir/MyFile.ext")