How can I convert Assembly.CodeBase into a filesystem path in C#?
我有一个项目,它将模板存储在靠近dlls和exe的
我想在运行时确定这个文件路径,但是使用一种可以在单元测试和生产中使用的技术(我不想在nunit中禁用阴影复制!)
1 | file:///D:/projects/MyApp/MyApp/bin/debug/MyApp.exe |
现在我可以使用字符串操作将其转换为本地文件系统路径,但我怀疑有一种更干净的方法可以将其隐藏在.NET框架的某个地方。有人知道推荐的方法吗?
(如果unc路径不是
您需要使用system.uri.localpath:
1 |
因此,如果需要当前正在执行的程序集的原始位置:
1 |
Assembly.CodeBase looks promising, but it's a UNC path:
请注意,它近似于文件URI,而不是UNC路径。
通过手工操作字符串来解决这个问题。说真的。
使用以下目录(逐字)尝试可以找到的所有其他方法:
1 2 | C:\Test\Space( )(h#)(p%20){[a&],t@,p%,+}., elease |
这是一个有效的(如果有点不寻常)Windows路径。(有些人在那里的路径中会有这两个字符中的任何一个,您希望您的方法适用于所有这些字符,对吗?)
可用的代码库(我们不需要
1 2 3 | 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 没有完全转义(我不知道这是bug还是uri方案的缺点):- 注意空格字符(
是如何翻译成 %20 的。 - 但是
%20 序列也翻译成%20 !(百分比% 根本没有逃逸) - 没有人能从这个残缺的形式重建原始!
- 注意空格字符(
对于本地文件(这正是我所关心的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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); } |
我相信人们可以想出更好的解决方案,如果是本地路径的话,也许人们甚至可以想出一个解决方案来对
这应该有效:
1 2 3 4 5 |
我使用它可以使用独立的log4net.config文件从dll库中进行日志记录。
还有一个解决方案,包括复杂路径:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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)); } |
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | [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,因此还可以使用
1 2 3 4 | using System.Reflection; using NUnit.Framework.Internal; ... string path = AssemblyHelper.GetDirectoryName(Assembly.GetExecutingAssembly()) |