在创建自定义MSBuild任务时,如何从C#代码获取当前项目目录?

sea*_*ean 117 c# msbuild

我希望获得当前的Project Dir,而不是运行其路径硬编码的外部程序.我正在使用自定义任务中的进程调用外部程序.

我该怎么办?AppDomain.CurrentDomain.BaseDirectory只是给了我VS 2008的位置.

moh*_*eeh 237

using System;
using System.IO;

// This will get the current WORKING directory (i.e. \bin\Debug)
string workingDirectory = Environment.CurrentDirectory;
// or: Directory.GetCurrentDirectory() gives the same result

// This will get the current PROJECT directory
string projectDirectory = Directory.GetParent(workingDirectory).Parent.FullName;
Run Code Online (Sandbox Code Playgroud)

  • 为Directory.GetParent()+1,所以我们没有得到\ bin\Debug目录:) (24认同)
  • 这个答案是错误的,因为它对项目配置做出了假设,因此它可能适用于某些项目,但不适用于其他项目。此外,所有评论说“这是正确答案”的人都是错误的;他们最多能说的是“它对我有用”,而它只对他们有用,因为月亮处于正确的相位并且行星对齐。更糟糕的是,如果您对项目配置进行更改,这个答案将停止为您工作,并且您将不会收到警告或指示原因。 (6认同)
  • 如果我们使用自定义目标CPU怎么办?例如,如果我将构建设置为目标x64,则会在其中创建另一个文件夹. (5认同)
  • 要获取项目文件路径,我们应该使用 Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent.Parent.Parent.FullName (3认同)
  • 这是正确的答案。接受的答案将返回bin目录的路径,该目录不是项目目录。 (2认同)
  • 运作良好,这应该是公认的答案 (2认同)

Ira*_*tro 105

您可以尝试这两种方法之一.

string startupPath = System.IO.Directory.GetCurrentDirectory();

string startupPath = Environment.CurrentDirectory;
Run Code Online (Sandbox Code Playgroud)

告诉我,哪一个对你好

  • 上面这两个指向bin目录,所以如果您有整个解决方案的一个bin目录,它将指向您而不是您的项目目录(或项目目录下面的两个级别) (76认同)
  • 使用测试资源管理器时,两种解决方案均无法正常工作。 (9认同)
  • 我想补充一点,这实际上是当前的答案。我选择了另一个答案,但这一直将我的文件放在 .NET 5.0 中当前工作目录的上方两级。我不得不回到这个答案,将文件放置在我当前的项目目录中。所以,这确实是正确的答案,至少在我的控制台 .NET 5 应用程序中是这样。 (2认同)

hin*_*531 24

如果项目Environment.CurrentDirectory在IIS Express 上运行,则可以指向IIS Express所在的位置(默认路径为C:\ Program Files(x86)\ IIS Express),而不是项目所在的位置.


这可能是各种项目最合适的目录路径.

AppDomain.CurrentDomain.BaseDirectory
Run Code Online (Sandbox Code Playgroud)

这是MSDN定义.

获取程序集解析程序用于探测程序集的基目录.

  • 9年后,有人确实有了真正的答案. (12认同)
  • @Latency 存在于 .net core 3 WPF 项目中 (2认同)

nh4*_*3de 17

这也将通过从当前执行目录导航两个级别来为您提供项目目录(这不会返回每个构建的项目目录,但这是最常见的).

System.IO.Path.GetFullPath(@"..\..\")
Run Code Online (Sandbox Code Playgroud)

当然,您希望在某种验证/错误处理逻辑中包含此内容.


abe*_*406 10

如果您不想知道解决方案所在的目录是什么,则需要执行以下操作:

 var parent = Directory.GetParent(Directory.GetCurrentDirectory()).Parent;
            if (parent != null)
            {
                var directoryInfo = parent.Parent;
                string startDirectory = null;
                if (directoryInfo != null)
                {
                    startDirectory = directoryInfo.FullName;
                }
                if (startDirectory != null)
                { /*Do whatever you want "startDirectory" variable*/}
            }
Run Code Online (Sandbox Code Playgroud)

如果只使用GetCurrrentDirectory()方法,则无论是调试还是发布,都会获得构建文件夹.我希望这有帮助!如果您忘记了验证,它将是这样的:

var startDirectory = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName;
Run Code Online (Sandbox Code Playgroud)


Fun*_*lad 8

如果您确实想确保获得源项目目录,无论 bin 输出路径设置为什么:

  1. 添加预构建事件命令行(Visual Studio:项目属性 -> 构建事件):

    echo $(MSBuildProjectDirectory) > $(MSBuildProjectDirectory)\Resources\ProjectDirectory.txt

  2. 将文件添加ProjectDirectory.txt到项目的Resources.resx中(如果尚不存在,右键单击项目 - >添加新项目 - >资源文件)

  3. 从代码访问Resources.ProjectDirectory

  • 这是这里唯一好的答案。由于我使用该目录进行单元测试,因此我这样做了: echo $(ProjectDir)>$(ProjectDir)\Input\ProjectDir.txt 然后我将 ProjectDir.txt 作为单元测试部署项包含在内。无论测试在哪里运行,我现在都有构建文件夹。 (2认同)

Jan*_*šeň 6

这个解决方案对我来说效果很好,在开发以及通过 C#使用ASP.NET MVC5 的TEST 和 PROD 服务器上:

var projectDir = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
Run Code Online (Sandbox Code Playgroud)

如果您需要项目配置文件中的项目目录,请使用:

$(ProjectDir)
Run Code Online (Sandbox Code Playgroud)


Chr*_*oma 6

string projPath = Path.GetFullPath(@"..\..\..\");
Console.WriteLine(projPath);
Run Code Online (Sandbox Code Playgroud)

这对我来说一直很有效。搏一搏。


Bre*_*ett 5

我也在寻找这个.我有一个运行HWC的项目,我想让网站远离应用程序树,但我不想将它保留在调试(或发布)目录中.FWIW,已接受的解决方案(以及此解决方案)仅标识可执行文件所在的目录.

为了找到该目录,我一直在使用

string startupPath = System.IO.Path.GetFullPath(".\\").
Run Code Online (Sandbox Code Playgroud)


小智 5

我也遇到过类似的情况,谷歌无果后,我声明了一个公共字符串,它修改了调试/发布路径的字符串值以获取项目路径。使用此方法的一个好处是,由于它使用当前项目的目录,因此无论您是在调试目录还是发布目录中工作都无关紧要:

public string DirProject()
{
    string DirDebug = System.IO.Directory.GetCurrentDirectory();
    string DirProject = DirDebug;

    for (int counter_slash = 0; counter_slash < 4; counter_slash++)
    {
        DirProject = DirProject.Substring(0, DirProject.LastIndexOf(@"\"));
    }

    return DirProject;
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以随时调用它,只需一行:

string MyProjectDir = DirProject();
Run Code Online (Sandbox Code Playgroud)

这在大多数情况下应该有效。


zwc*_*oud 5

基于Gucu112的答案,但对于.NET Core控制台/窗口应用程序,应为:

string projectDir = 
    Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\.."));
Run Code Online (Sandbox Code Playgroud)

我正在xUnit项目的.NET Core窗口应用程序中使用它。


Jef*_*THU 5

using System;
using System.IO;

// Get the current directory and make it a DirectoryInfo object.
// Do not use Environment.CurrentDirectory, vistual studio 
// and visual studio code will return different result:
// Visual studio will return @"projectDir\bin\Release\netcoreapp2.0\", yet 
// vs code will return @"projectDir\"
var currentDirectory = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);

// On windows, the current directory is the compiled binary sits,
// so string like @"bin\Release\netcoreapp2.0\" will follow the project directory. 
// Hense, the project directory is the great grand-father of the current directory.
string projectDirectory = currentDirectory.Parent.Parent.Parent.FullName;
Run Code Online (Sandbox Code Playgroud)


Mik*_*kis 5

我对迄今为止发布的所有解决方案的随意性感到惊讶。

获取 C# 项目根文件夹的唯一正确方法是利用该[CallerFilePath]属性获取源文件的完整路径名,然后从中减去文件名和扩展名,剩下项目的路径。

以下是实际操作方法:

在项目的根文件夹中,添加ProjectSourcePath.cs具有以下内容的文件:

internal static class ProjectSourcePath
{
    private const  string  myRelativePath = nameof(ProjectSourcePath) + ".cs";
    private static string? lazyValue;
    public  static string  Value => lazyValue ??= calculatePath();

    private static string calculatePath()
    {
        string pathName = GetSourceFilePathName();
        Assert( pathName.EndsWith( myRelativePath, StringComparison.Ordinal ) );
        return pathName.Substring( 0, pathName.Length - myRelativePath.Length );
    }
}
Run Code Online (Sandbox Code Playgroud)

string?要求的C#与一个漂亮的晚版#nullable enable; 如果你没有它,那么只需删除?.

Assert()功能是我自己,用自己的替换它。

该函数GetSourceFilePathName()定义如下:

using System.Runtime.CompilerServices

    public static string GetSourceFilePathName( [CallerFilePath] string? callerFilePath = null ) //
        => callerFilePath ?? "";
Run Code Online (Sandbox Code Playgroud)

一旦你有了这个,你可以按如下方式使用它:

string projectSourcePath = ProjectSourcePath.Value;
Run Code Online (Sandbox Code Playgroud)

  • @NotAPro 当然我可以,但是这样做我会得到什么?如果你看一下 `Directory.GetParent()` 的源代码,它会做很多奇怪的事情,包括路径规范化(这是不必要的,因为 `CallerFilePath` 已经产生了一个规范化的路径),最后奇怪的东西,它对最后一个分隔符字符的索引进行低效的反向线性搜索(我已经通过 `pathName.Length - myRelativePath.Length` 知道了),最后只调用了... `Substring() `。那么,为什么要这样做而不是仅仅使用“Substring()”呢? (5认同)
  • 这很好。干得好,谢谢 (3认同)
  • 我知道,这已经很老了,但我认为值得一提的是,只有当您在执行该项目的同一台机器上编译该项目时,这才有效。也许这隐含在原来的问题中,我不能说。无论如何,对于未来的谷歌用户,请注意,这将在编译期间内联计算机上文件的实际绝对路径,因此它是不可移植的。 (3认同)
  • @MikeNakis 很好,不知道所有这些,我认为 `GetParent` 看起来更好,因为你不必弄清楚子字符串算术;但话虽如此,“Substring”更有意义。 (2认同)