如何将Assembly.CodeBase转换为C#中的文件系统路径?

Dyl*_*tie 60 .net c# nunit codebase

我有一个项目,将模板存储在\TemplatesDLL和EXE旁边的文件夹中.

我想在运行时确定这个文件路径,但使用的技术可以在单元测试和生产中使用(我不想在NUnit中禁用阴影复制!)

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

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

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

file:///D:/projects/MyApp/MyApp/bin/debug/MyApp.exe
Run Code Online (Sandbox Code Playgroud)

现在我可以使用字符串操作将其转换为本地文件系统路径,但我怀疑有一种更简洁的方法可以将它隐藏在.NET框架中.有人知道这样做的推荐方法吗?

(如果UNC路径不是file:///URL,则抛出异常在此上下文中绝对正常)

Pol*_*fun 107

您需要使用System.Uri.LocalPath:

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

因此,如果您想要当前正在执行的程序集的原始位置:

string localPath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath;
Run Code Online (Sandbox Code Playgroud)

  • 请注意,当目录名称中包含"#"时,这不起作用 (6认同)
  • 这里的关键是使用`Uri.LocalPath` - 我们有一个bug,我们使用`Uri.AbsolutePath`,这似乎有效,直到路径名中有空格! (3认同)

Mar*_* Ba 24

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

请注意,这是一些近似文件URI,没有一个UNC路径.


你可以通过手工操作字符串来解决这个问题.认真.

尝试使用以下目录在SO上找到的所有其他方法(逐字):

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

这是一个有效的,如果有点不寻常的Windows路径.(有些人在路径中有这些角色中的任何一个,你会希望你的方法适用于所有这些,对吧?)

那么可用的代码库(我们不想要Location,对吧?)属性(在我的带有.NET 4的Win7上):

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
Run Code Online (Sandbox Code Playgroud)

你会注意到:

  • 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);
    }
Run Code Online (Sandbox Code Playgroud)

我相信人们可以提出更好的解决方案,可能有人甚至可以提出一个解决方案,CodeBase如果它是一个本地路径,它可以对属性进行正确的URL连接/解码,但考虑到可以解决这个问题file:///并完成它,我会说这个解决方案代表好就够了,如果一定真难看.


mmm*_*mmm 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");
Run Code Online (Sandbox Code Playgroud)

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