如何在C#中将Assembly.CodeBase转换为文件系统路径?
如何在C#中将Assembly.CodeBase转换为文件系统路径?
我有一个项目,将模板存储在与DLL和EXE相邻的\\Templates
文件夹中。
我想在运行时确定此文件路径,但要使用一种技术,既适用于单元测试,也适用于生产环境(我不想在NUnit中禁用阴影复制!)
Assembly.Location
无法使用,因为在NUnit下运行时它返回阴影复制的程序集路径。
Environment.CommandLine
也有限制,因为在NUnit等中,它返回到NUnit而不是我的项目的路径。
Assembly.CodeBase
看起来很有希望,但它是一个UNC路径:
file:///D:/projects/MyApp/MyApp/bin/debug/MyApp.exe
现在,我可以使用字符串操作将其转换为本地文件系统路径,但我怀疑.NET框架中有一个更简洁的方法。 有人知道推荐的方法吗?
(如果UNC路径不是file:///
URL,则在此上下文中引发异常是完全可以的)
Assembly.CodeBase看起来很有前途,但它是一个UNC路径:
您需要手动进行字符串操作来解决这个问题,真的。
尝试所有您可以在SO上找到的其他方法,使用以下目录(逐字逐句):
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); }
我相信人们可以提出更好的解决方案,可能还可以想出一个解决方案,在本地路径的CodeBase
属性进行适当的URL编码/解码,但是鉴于您只需剥离file:///
并完成它,我认为这个解决方案已经足够好了,尽管确实非常丑陋。
你需要使用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;
LocalPath包括程序集的文件名,例如:
D:\projects\MyApp\MyApp\bin\debug\MyApp.exe
如果你想获得程序集的目录,那么使用System.IO.Path.GetDirectoryName():
string localDirectory = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
这将给你:
D:\projects\MyApp\MyApp\bin\debug