Как получить путь к сборке, в которой находится код?

есть ли способ получить путь для сборки, в которой находится текущий код? Мне не нужен путь вызывающей сборки, только тот, который содержит код.

В основном мой модульный тест должен прочитать некоторые тестовые файлы xml, которые расположены относительно dll. Я хочу, чтобы путь всегда разрешался правильно, независимо от того, выполняется ли тестовая dll TestDriven.NET, графический интерфейс MbUnit или что-то еще.

редактировать: люди, кажется, быть не понимаю, о чем я спрашиваю.

моя тестовая библиотека находится в say

C:projectsmyapplicationdaotestsbinDebugdaotests.dll файлы

и я хотел бы сделать этот путь:

C:projectsmyapplicationdaotestsbinDebug

три предложения до сих пор терпят неудачу, когда я бегу от Mbunit Gui:

  • Environment.CurrentDirectory дает c:Program Файлы MbUnit

  • System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location дает C:Documents и Настройкиgeorgeлокальный НастройкиTemp .... DaoTests.dll файлы

  • System.Reflection.Assembly.GetExecutingAssembly().Location дает то же самое, что и предыдущий.

26 ответов


Я определил следующее свойство, поскольку мы часто используем его в модульном тестировании.

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's 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();

единственным решением, которое сработало для меня при использовании общих сетевых ресурсов CodeBase и UNC, было:

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

Он также работает с обычными URIs тоже.


Это должно работать, если сборка не теневое копирование:

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

Я подозреваю, что реальная проблема здесь в том, что ваш тестовый бегун копирует вашу сборку в другое место. Во время выполнения невозможно определить, откуда была скопирована сборка, но вы, вероятно, можете щелкнуть переключатель, чтобы сообщить тестовому бегуну запустить сборку оттуда, где она находится, а не копировать ее в теневой каталог.

такой переход, вероятно, будет отличаться для каждого теста, конечно.

рассматривали ли вы возможность внедрения XML-данных в качестве ресурсов внутри вашей тестовой сборки?


Как насчет этого:

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

AppDomain.CurrentDomain.BaseDirectory

работает с MBUNIT GUI.


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

вот 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 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 говорит:

"кодовая база-это URL-адрес места, где был найден файл, а местоположение-путь, по которому он был фактически загружен. Например, если сборка была загружена из интернета, Кодовая база может начинаться с " http://", но ее расположение может начинаться с"C:\". Если файл был скопирован тенью, то местом будет путь к копии файла в директории теневой копии. Также полезно знать, что кодовая база не гарантируется для сборок в GAC. Однако расположение всегда будет установлено для сборок, загружаемых с диска."

вы мая хотите использовать кодовую базу вместо местоположения.


за все эти годы, никто на самом деле упоминал об этом. Трюк, который я узнал от awesome проект ApprovalTests. Фокус в том, что вы используете отладочную информацию в сборке, чтобы найти исходный каталог.

это не будет работать в режиме выпуска, ни с включенной оптимизацией, ни на машине, отличной от той, на которой она была скомпилирована.

но это даст вам пути, которые являются относительно расположения файл исходного кода, который вы вызываете из

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

текущий каталог, в котором вы существуете.

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;

насколько я могу судить, большинство других ответов есть несколько проблем.

правильный способ сделать это для disk-based (в отличие от web-based), non-GACed assembly должен использоватьCodeBase собственность.

это возвращает URL (file://). Вместо того, чтобы возиться с строковые манипуляции или UnescapeDataString, это может быть преобразовано с минимальной суетой, используя LocalPath собственность Uri.

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

Как насчет этого ...

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

тогда просто отрежьте то, что вам не нужно


вы можете получить бин пути домен приложений.CurrentDomain.RelativeSearchPath


все предлагаемые ответы работают, когда разработчик может изменить код, чтобы включить необходимый фрагмент, но если вы хотите сделать это без изменения кода, Вы можете использовать Process Explorer.

Он будет перечислять все исполняемые библиотеки DLL в системе, вам может потребоваться определить идентификатор процесса вашего запущенного приложения, но это обычно не слишком сложно.

Я написал полное описание того, как это сделать для dll внутри II - http://nodogmablog.bryanhogan.net/2016/09/locating-and-checking-an-executing-dll-on-a-running-web-server/


в приложении windows form вы можете просто использовать Application.StartupPath

но для DLL и консольных приложений код намного сложнее запомнить...

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

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

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

вот что я придумал. между веб-проектами, модульными тестами (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).


Я нахожу свое решение адекватным для поиска местоположения.

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

я получил такое же поведение в NUnit в прошлом. По умолчанию NUnit копирует сборку в каталог temp. Вы можете изменить это поведение в NUnit параметры:

enter image description here

может быть TestDriven.NET и MbUnit GUI имеют те же настройки.


Я использую это, чтобы получить путь к каталогу bin:

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

в результате:

"c:\users\ricooley\documents\visual студия 2010\проекты\Windows_Test_Project\Windows_Test_Project\bin"


веб-приложения?

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