Как я могу преобразовать сборку.Кода в путь файловой системы в C#?
у меня есть проект, который хранит шаблоны в Templates
папка рядом с dll и EXE.
Я хочу определить этот путь к файлу во время выполнения, но используя метод, который будет работать внутри модульного теста, а также в производстве (и я не хочу отключать теневое копирование в NUnit!)
Assembly.Location
не годится, потому что он возвращает путь скопированной тенью сборки при запуске под NUnit.
Environment.CommandLine
также имеет ограниченное использование, потому что в NUnit et al он возвращается путь к Нанит, не мой проект.
Assembly.CodeBase
выглядит многообещающе, но это путь UNC:
file:///D:/projects/MyApp/MyApp/bin/debug/MyApp.exe
Теперь может превратите это в локальный путь файловой системы с помощью Строковой манипуляции, но я подозреваю, что есть более чистый способ сделать это где-то в .NET framework. Кто-нибудь знает рекомендуемый способ сделать это?
(выбрасывание исключения, если путь UNC не является file:///
URL абсолютно нормально в этом контексте)
5 ответов:
вы должны использовать систему.Ури.LocalPath:
string localPath = new Uri("file:///D:/projects/MyApp/MyApp/bin/debug/MyApp.exe").LocalPath;
Итак, если вы хотите Исходное расположение текущей исполняемой сборки:
string localPath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath;
сборка.Кодовая база выглядит многообещающе, но это UNC-путь:
обратите внимание, что это что-то приближается a файл uri,не an UNC path.
вы решаете это, делая манипуляции со строками вручную. серьезно.
попробуйте все другие методы, которые вы можете найти на SO со следующим каталогом (дословно):
C:\Test\Space( )(h#)(p%20){[a&],t@,p%,+}.,\Release
это допустимо, если несколько необычный, Windows path. (Некоторые люди будет есть либо один из этих символов там пути, и вы хотели бы, чтобы вы метод для работы все из этих, верно?)
доступная база кода (мы не хотим
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):
- обратите внимание, как пробел (
) translates to
%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 en - / декодирование
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.конфигурационный файл.
еще одно решение, включая сложные пути:
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)); }