我有一个将模板存储在一个的项目 \Templates 文件夹在DLL和EXE旁边。

我想在运行时确定此文件路径,但是使用将在单元测试和生产中使用的技术(我不想在Nunit中禁用影子复制!)

Assembly.Location 之所以不好,是因为它在Nunit下运行时会返回影子封面的组合路径。

Environment.CommandLine 也有限使用,因为在Nunit等人中,它将通往Nunit的道路而不是我的项目返回。

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

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

现在我 可以 使用字符串操纵将其变成本地文件系统路径,但我怀疑有一种更干净的方法将其埋在某个地方的.NET框架中。有人知道建议这样做吗?

(如果UNC路径不是一个例外 file:/// 在这种情况下,URL绝对很好)

有帮助吗?

解决方案

您需要使用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;

其他提示

汇编。代表看起来很有希望,但这是一个UNC路径:

请注意,这是近似的东西 文件URI, 不是 一个 UNC路径.


您可以通过手动进行绳子操作来解决此问题。 严重地。

尝试使用以下目录(Verbatim)的所有其他方法:

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

我确定可以提出更好的解决方案,甚至可能提出一个解决方案,以适当的URL启用/解码 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");

我正在使用它来使用独立的log4net.config文件从dll库中登录。

另一种解决方案,包括复杂的路径:

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

既然您标记了这个问题 Nunit, ,您也可以使用 AssemblyHelper.GetDirectoryName 要获取执行组件的原始目录:

using System.Reflection;
using NUnit.Framework.Internal;
...
string path = AssemblyHelper.GetDirectoryName(Assembly.GetExecutingAssembly())
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top