Как я могу конвертировать сборку. Кодбаза в путь файловой системы в C #?

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

  •  29-09-2019
  •  | 
  •  

Вопрос

У меня есть проект, который хранит шаблоны в \Templates папка рядом с dlls и exe.

Я хочу определить этот путь к файлу во время выполнения, но используя методику, которая будет работать внутри теста на единицу, а также в производстве (и я не хочу отключить тень-копирование в Nunit!)

Assembly.Location это нехорошо, потому что он возвращает путь, закрепленный тенью, при беге под NUNIT.

Environment.CommandLine Также имеет ограниченное использование, потому что в NUNIT et al возвращает путь к NUNIT, а не в моем проекте.

Assembly.CodeBase выглядит многообещающе, но это путь UNC:

file:///D:/projects/MyApp/MyApp/bin/debug/MyApp.exe

Сейчас я мог Превратите это в локальную путь файловой системы, используя манипуляции с строками, но я подозреваю, что где -нибудь есть более чистый способ сделать это в .NET Framework. Кто -нибудь знает рекомендуемый способ сделать это?

(Бросает исключение, если путь UNC не является file:/// URL абсолютно в порядке в этом контексте)

Это было полезно?

Решение

Вам нужно использовать system.uri.localpath:

string localPath = new Uri("file:///D:/projects/MyApp/MyApp/bin/debug/MyApp.exe").LocalPath;

Так что, если вы хотите исходное местоположение в настоящее время выполняемой сборки:

string localPath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath;

Другие советы

Сборка. Кодебаза выглядит многообещающе, но это путь UNC:

Обратите внимание, что это что-то приближающееся к Файл URI, нет атмосфера Уклон.


Вы решаете это, делая манипуляцию строки вручную. Шутки в сторону.

Попробуйте все остальные методы, которые вы можете найти в следующем каталоге (дослов):

C:\Test\Space( )(h#)(p%20){[a&],t@,p%,+}.,\Release

Это действительна, если несколько необычно, путь Windows. (Некоторые люди будем есть один из этих персонажей там, и вы бы хотели, чтобы вы работали над все из них, верно?)

Доступная база кода (мы не хотим Location, Правильно?) свойства тогда (на моем win7 с .net 4):

assembly.CodeBase -> file:///C:/Test/Space( )(h#)(p%20){[a&],t@,p%,+}.,/Release

assembly.EscapedCodeBase -> file:///C:/Test/Space(%20)(h%23)(p%20)%7B%5Ba%26%5D,t@,p%,+%7D.,/Release

Вы заметите:

  • CodeBase вообще не сбежал, это просто обычный локальный путь file:/// и обратные склады заменены. Как таковой, это не работать, чтобы накормить это System.Uri.
  • EscapedCodeBase не сбежается полностью (я делаю нет знать, является ли это ошибкой или это недостаток Схема URI):
    • Обратите внимание, как пространственный символ () переводится на %20
    • но %20 последовательность также переводится %20Действительно (процентов % не избежается вообще)
    • Никто Может восстановить оригинал из этой потрясенной формы!

Для локальных файлов (и это действительно все, что мне волнует CodeBaseвещи, потому что если файл не локальный, вы, вероятно, хотите использовать .Location В любом случае, следующее работает для меня (обратите внимание, что это тоже не самый красивый:

    public static string GetAssemblyFullPath(Assembly assembly)
    {
        string codeBasePseudoUrl = assembly.CodeBase; // "pseudo" because it is not properly escaped
        if (codeBasePseudoUrl != null) {
            const string filePrefix3 = @"file:///";
            if (codeBasePseudoUrl.StartsWith(filePrefix3)) {
                string sPath = codeBasePseudoUrl.Substring(filePrefix3.Length);
                string bsPath = sPath.Replace('/', '\\');
                Console.WriteLine("bsPath: " + bsPath);
                string fp = Path.GetFullPath(bsPath);
                Console.WriteLine("fp: " + fp);
                return fp;
            }
        }
        System.Diagnostics.Debug.Assert(false, "CodeBase evaluation failed! - Using Location as fallback.");
        return Path.GetFullPath(assembly.Location);
    }

Я уверен, что можно придумать лучшие решения, вероятно, можно даже придумать решение, которое выполняет правильный URL-адрес CodeBase имущество, если это локальный путь, но учитывая, что можно просто раздеть file:/// И делать с этим, я бы сказал, что это решение стоит достаточно хорошее, если безусловно Действительно уродливо.

Это должно работать:

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.config.

Еще одно решение, включая сложные пути:

    public static string GetPath(this Assembly assembly)
    {
        return Path.GetDirectoryName(assembly.GetFileName());
    }

    public static string GetFileName(this Assembly assembly)
    {
        return assembly.CodeBase.GetPathFromUri();
    }

    public static string GetPathFromUri(this string uriString)
    {
        var uri = new Uri(Uri.EscapeUriString(uriString));
        return String.Format("{0}{1}", Uri.UnescapeDataString(uri.PathAndQuery), Uri.UnescapeDataString(uri.Fragment));
    }

и тесты:

    [Test]
    public void GetPathFromUriTest()
    {
        Assert.AreEqual(@"C:/Test/Space( )(h#)(p%20){[a&],t@,p%,+}.,/Release", @"file:///C:/Test/Space( )(h#)(p%20){[a&],t@,p%,+}.,/Release".GetPathFromUri());
        Assert.AreEqual(@"C:/Test/Space( )(h#)(p%20){[a&],t@,p%,+}.,/Release",  @"file://C:/Test/Space( )(h#)(p%20){[a&],t@,p%,+}.,/Release".GetPathFromUri());
    }

    [Test]
    public void AssemblyPathTest()
    {
        var asm = Assembly.GetExecutingAssembly();

        var path = asm.GetPath();
        var file = asm.GetFileName();

        Assert.IsNotEmpty(path);
        Assert.IsNotEmpty(file);

        Assert.That(File     .Exists(file));
        Assert.That(Directory.Exists(path));
    }

Поскольку вы отметили этот вопрос NUNIT, вы также можете использовать AssemblyHelper.GetDirectoryName Чтобы получить оригинальный каталог выполненной сборки:

using System.Reflection;
using NUnit.Framework.Internal;
...
string path = AssemblyHelper.GetDirectoryName(Assembly.GetExecutingAssembly())
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top