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

StackOverflow https://stackoverflow.com/questions/52797

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

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

Моя тестовая библиотека находится, скажем, в

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

и я хотел бы пройти этот путь:

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

Три предложения до сих пор подводили меня, когда я запускался из графического интерфейса MbUnit:

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

  • System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location дает C:\Documents и Настройки \george\Local Настройки emp\ ....\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'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);

Это также работает и с обычными URI.

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

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

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

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

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

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

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

AppDomain.CurrentDomain.BaseDirectory

работает с графическим интерфейсом MbUnit.

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

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

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

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

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

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;

Я использовал сборку.Кодовая база вместо местоположения:

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.Однако для сборок, загруженных с диска, всегда будет задано местоположение."

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

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

Правильный способ сделать это для сборка на диске (в отличие от веб-сборки), не привязанная к сети заключается в использовании текущей выполняемой сборки CodeBase собственность.

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

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

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

Это не будет работать ни в режиме ВЫПУСКА, ни при включенной оптимизации, ни на компьютере, отличном от того, на котором оно было скомпилировано.

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

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

Путь к ячейке можно получить с помощью AppDomain.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);

Вы получите неверный каталог, если путь содержит символ '#'.Поэтому я использую модификацию ответа Джона Сибли, которая представляет собой комбинацию UriBuilder.Path и UriBuilder.Фрагмент:

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

Это то, что я придумал. В перерывах между веб-проектами - модульные тесты (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 копирует вашу сборку во временный каталог.Вы можете изменить это поведение в NUnit Настройки:

enter image description here

Может быть TestDriven.NET и MbUnit Графический интерфейс имеет те же настройки.

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

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

Вы получаете такой результат:

"c:\users icooley\documents\visual studio 2010\Проекты\Windows_Test_Project\Windows_Test_Project\bin"

Веб-приложение?

Server.MapPath("~/MyDir/MyFile.ext")
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top