2010-11-05 200 views
43

我有一个项目,将模板存储在DLL和EXE旁边的\Templates文件夹中。如何将Assembly.CodeBase转换为C#中的文件系统路径?

我想在运行时确定该文件的路径,但使用的技术,将生产一个单元测试内部以及工作(我不想在NUnit的禁用阴影复制!)

Assembly.Location不好,因为它在NUnit下运行时会返回阴影复制程序集的路径。

Environment.CommandLine也是有限的使用,因为在NUnit等它返回的路径NUnit,而不是我的项目。

Assembly.CodeBase看起来很有希望,但它是一个UNC路径:

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

现在我可以使用字符串操作变成一个本地文件系统的路径,但我怀疑有它埋在做的更清洁的方式.NET框架的某处。任何人都知道这样做的推荐方式?如果你想

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

所以:

+0

possible dupl [是否有一个.NET Framework方法将文件URI转换为带有驱动器号的路径?](http://stackoverflow.com/questions/278761/is-there-a-net-framework-method-for-converting-文件-Uris-to-paths-with-drive-le) – nawfal 2014-01-10 20:04:25

回答

87

您需要使用System.Uri.LocalPath(如果UNC路径不是file:/// URL是绝对罚款在这种情况下抛出一个异常)当前执行的程序集的原始位置:

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

美丽。非常感谢。 – 2010-11-05 16:23:28

+0

Awesomeballs!谢谢你,谢谢你,谢谢你! – 2013-07-16 02:36:46

+4

请注意,当目录名称中有'#'时,这不起作用 – drake7707 2014-02-01 10:20:51

5

这应该工作:

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

我使用它可以使用独立的log4net.config文件从dll库中进行登录。

17

Assembly.CodeBase看起来很有希望,但它是一个UNC路径:

请注意,这是什么近似file uriUNC path


你可以通过手动进行字符串操作来解决这个问题。 严重。

尝试所有其他方法,你可以找到使之与下面的目录(逐字):

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

这是一个有效的,如果有些不寻常,Windows路径。 (有些人在那里路径这些字符中的任何一个,你会想你的方法为那些所有工作,对吧?)

可用的代码库(we do not want Location, right?)的属性然后(上我的Win7与。NET 4):

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

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

你会注意到:

  • CodeBase没有逃脱的话,那只是与file:///前缀常规本地路径和反斜杠替换。因此,它工作饲料到System.Uri
  • EscapedCodeBase没有完全逃脱(我做知道这是一个错误,或者如果这是URI scheme的缺点):
    • 注意空格字符()如何转化为%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:///我会说这个解决方案足够好,如果肯定真的很难看。

+1

如果是UNC路径,它是file://server/share/path/to/assembly.dll(只有2个斜杠)。 – Joshua 2016-08-02 23:18:01

+0

@Joshua - 你的意思是说一个'\\ server \ ...'路径只有两个斜杠编码,而不是三个本地驱动器? – 2016-08-03 07:41:35

+0

@Joshua - 你知道'\\?\ UNC \ server \ share'路径是如何编码的吗? – 2016-08-03 07:42:40

1

既然你标记这个问题NUnit的,你也可以用AssemblyHelper.GetDirectoryName得到执行的程序集的原目录:

using System.Reflection; 
using NUnit.Framework.Internal; 
... 
string path = AssemblyHelper.GetDirectoryName(Assembly.GetExecutingAssembly()) 
2

还有一个解决方案,包括复杂的路径:

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&],[email protected],p%,+}.,/Release", @"file:///C:/Test/Space()(h#)(p%20){[a&],[email protected],p%,+}.,/Release".GetPathFromUri()); 
     Assert.AreEqual(@"C:/Test/Space()(h#)(p%20){[a&],[email protected],p%,+}.,/Release", @"file://C:/Test/Space()(h#)(p%20){[a&],[email protected],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)); 
    } 
+0

不错!但我更喜欢反斜杠,所以我会通过'Path.GetFullPath'传递'GetPathFromUri'的结果。 – tm1 2017-06-13 08:33:40

+0

您需要考虑Uri.Host以支持网络路径。 – tm1 2017-06-23 06:28:28

相关问题