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

时间:2009-05-03 08:14:58

标签: c# msbuild

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

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

23 个答案:

答案 0 :(得分:210)

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;

答案 1 :(得分:97)

您可以尝试以下两种方法之一。

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

string startupPath = Environment.CurrentDirectory;

告诉我,你觉得哪一个更好

答案 2 :(得分:16)

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

System.IO.Path.GetFullPath(@"..\..\")

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

答案 3 :(得分:13)

如果一个项目正在IIS Express上运行,则Environment.CurrentDirectory可能指向IIS Express所在的位置(默认路径为 C:\ Program Files(x86)\ IIS Express >),而不是您的项目所在的地方。


对于各种项目,这可能是最合适的目录路径。

AppDomain.CurrentDomain.BaseDirectory

这是MSDN定义。

  

获取程序集解析器用来探测程序集的基本目录。

答案 4 :(得分:9)

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

 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*/}
            }

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

var startDirectory = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName;

答案 5 :(得分:5)

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

要查找该目录,我一直在使用

string startupPath = System.IO.Path.GetFullPath(".\\").

答案 6 :(得分:4)

又一个不完美的解决方案(但也许比其他一些更接近完美):

    protected static string GetSolutionFSPath() {
        return System.IO.Directory.GetParent(System.IO.Directory.GetCurrentDirectory()).Parent.Parent.FullName;
    }
    protected static string GetProjectFSPath() {
        return String.Format("{0}\\{1}", GetSolutionFSPath(), System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
    }

即使当前项目不是解决方案的Startup Project,此版本也会返回当前项目' 文件夹。

第一个缺陷就是我已经跳过所有错误检查。这可以很容易修复,但如果您将项目存储在驱动器的根目录中或使用路径中的联结(并且该联结是解决方案文件夹的后代),则应该只是一个问题,因此这种情况不太可能。我还不完全确定Visual Studio无论如何都可以处理这些设置。

您可能遇到的另一个(更可能的)问题是项目名称​​必须匹配项目的文件夹名称才能找到它。

您可能遇到的另一个问题是项目必须位于解决方案文件夹中。这通常不是问题,但如果您使用Add Existing Project to Solution选项将项目添加到解决方案中,那么这可能不是您的解决方案的组织方式。

最后,如果您的应用程序将修改工作目录,则应在执行此操作之前存储此值,因为此值是相对于当前工作目录确定的。

当然,这一切也意味着您不得更改项目的默认值'项目属性对话框中的Build - > Output pathDebug - > Working directory选项。

答案 7 :(得分:4)

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

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

string? 需要带有 #nullable enable 的相当新的 C# 版本;如果您没有它,则只需删除 ?

Assert() 函数是我自己的,请替换为你自己的。

函数GetSourceFilePathName()定义如下:

using System.Runtime.CompilerServices

    public static string GetSourceFilePathName( [CallerFilePath] string? callerFilePath = null ) //
        => callerFilePath ?? "";

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

string projectSourcePath = ProjectSourcePath.Value;

答案 8 :(得分:4)

另一种方法

string startupPath = System.IO.Directory.GetParent(@"./").FullName;

如果您想获取bin文件夹的路径

string startupPath = System.IO.Directory.GetParent(@"../").FullName;

也许有更好的方法=)

答案 9 :(得分:3)

使用它来获取Project目录(为我工作):

string projectPath = 
    Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;

答案 10 :(得分:3)

尝试一下,很简单

HttpContext.Current.Server.MapPath("~/FolderName/");

答案 11 :(得分:3)

在我最终完成关于我们公共字符串的第一个答案以获得答案之后,我突然意识到你可能从注册表中读取一个值来获得你想要的结果。事实证明,这条路线更短:

首先,您必须包含Microsoft.Win32命名空间,以便您可以使用注册表:

using Microsoft.Win32;    // required for reading and / or writing the registry

这是主要代码:

RegistryKey Projects_Key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\9.0", false);
string DirProject = (string)Projects_Key.GetValue(@"DefaultNewProjectLocation");

关于这个答案的说明:

我正在使用Visual Studio 2008专业版。如果您使用的是其他版本(即2003,2005,2010;等),那么您可能必须修改SubKey字符串的“版本”部分(即8.0,7.0等)。

如果你使用我的一个答案,如果没有太多要求,那么我想知道你使用了哪种方法以及为什么。祝好运。

  • DM

答案 12 :(得分:3)

我遇到了类似的情况,在无用的Googles之后,我声明了一个公共字符串,它修改了调试/释放路径的字符串值以获取项目路径。使用此方法的一个好处是,因为它使用当前项目的目录,所以如果您使用的是调试目录或发布目录,则不重要:

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

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

string MyProjectDir = DirProject();

这应该适用于大多数案例。

答案 13 :(得分:2)

基于Gucu112's answer,但对于.NET Core控制台/窗口应用程序,它应为:

string projectDir = 
    Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\.."));

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

答案 14 :(得分:2)

尝试:

var pathRegex = new Regex(@"\\bin(\\x86|\\x64)?\\(Debug|Release)$", RegexOptions.Compiled);
var directory = pathRegex.Replace(Directory.GetCurrentDirectory(), String.Empty);

此解决方案与其他解决方案不同,它也考虑了可能的x86或x64构建。

答案 15 :(得分:1)

我使用以下解决方案来完成工作:

string projectDir =
    Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\.."));

答案 16 :(得分:1)

此解决方案对我来说非常有效,在开发以及通过C#使用 ASP.NET MVC5的TEST和PROD服务器上

var projectDir = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);

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

$(ProjectDir)

答案 17 :(得分:0)

最佳解决方案

string PjFolder1 =
    Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).
        Parent.Parent.FullName;

其他解决方案

string pjFolder2 = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(
                System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)));

测试一下,AppDomain.CurrentDomain.BaseDirectory在过去的项目中为我工作了,现在我得到了调试文件夹....选定的“好答案”只是不起作用!。

//Project DEBUG folder, but STILL PROJECT FOLDER
string pjDebugFolder = AppDomain.CurrentDomain.BaseDirectory;

//Visual studio folder, NOT PROJECT FOLDER
//This solutions just not work
string vsFolder = Directory.GetCurrentDirectory();
string vsFolder2 = Environment.CurrentDirectory;
string vsFolder3 = Path.GetFullPath(".\\");   

//Current PROJECT FOLDER
string ProjectFolder = 
    //Get Debug Folder object from BaseDirectory ( the same with end slash)
    Directory.GetParent(pjDebugFolder).
    Parent.//Bin Folder object
    Parent. //Project Folder object
    FullName;//Project Folder complete path

答案 18 :(得分:0)

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

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

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

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

  3. 使用Resources.ProjectDirectory从代码访问。

答案 19 :(得分:0)

using System;
using System.IO;

// Get the current directory and make it a DirectoryInfo object.
var currentDirectory = new DirectoryInfo(Environment.CurrentDirectory);

// 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;

答案 20 :(得分:-1)

我知道这篇文章很老了。实际上,我自己也在寻找解决方案。一些解决方案已经发布,但它们很长,所以我决定编写自己的版本。

Directory.GetParent("./../..")

基本上它的作用是:

  1. . = 会将您留在当前所在的目录中。
  2. / = 在此上下文中,目录分隔符。
  3. .. = 将您移回一个目录 (2x)。
  4. GetParent() = 获取 ./../.. 的父文件夹

将所有这些结合在一起将为您留下: C:\Users\Oushima\Desktop\Homework\OoP\Assignment 1\part 1,(\part 1 是我的项目文件夹)。

这对我有用。它与 .Parent.Parent 非常相似,但更短。我希望这会帮助其他人。

如果您希望它 100% 返回字符串数据类型,那么您可以将 .FullName 放在它后面。哦,还有,别忘了 using System.IO; C# 参考。

答案 21 :(得分:-1)

这适用于带有SDK Core MSBuild配置的VS2017。

您需要使用EnvDTE / EnvDTE80软件包中的NuGet。

请勿使用COM或互操作。什么...垃圾!

 internal class Program {
    private static readonly DTE2 _dte2;

    // Static Constructor
    static Program() {
      _dte2 = (DTE2)Marshal.GetActiveObject("VisualStudio.DTE.15.0");
    }


    private static void FindProjectsIn(ProjectItem item, List<Project> results) {
      if (item.Object is Project) {
        var proj = (Project) item.Object;
        if (new Guid(proj.Kind) != new Guid(Constants.vsProjectItemKindPhysicalFolder))
          results.Add((Project) item.Object);
        else
          foreach (ProjectItem innerItem in proj.ProjectItems)
            FindProjectsIn(innerItem, results);
      }

      if (item.ProjectItems != null)
        foreach (ProjectItem innerItem in item.ProjectItems)
          FindProjectsIn(innerItem, results);
    }


    private static void FindProjectsIn(UIHierarchyItem item, List<Project> results) {
      if (item.Object is Project) {
        var proj = (Project) item.Object;
        if (new Guid(proj.Kind) != new Guid(Constants.vsProjectItemKindPhysicalFolder))
          results.Add((Project) item.Object);
        else
          foreach (ProjectItem innerItem in proj.ProjectItems)
            FindProjectsIn(innerItem, results);
      }

      foreach (UIHierarchyItem innerItem in item.UIHierarchyItems)
        FindProjectsIn(innerItem, results);
    }


    private static IEnumerable<Project> GetEnvDTEProjectsInSolution() {
      var ret = new List<Project>();
      var hierarchy = _dte2.ToolWindows.SolutionExplorer;
      foreach (UIHierarchyItem innerItem in hierarchy.UIHierarchyItems)
        FindProjectsIn(innerItem, ret);
      return ret;
    }


    private static void Main() {
      var projects = GetEnvDTEProjectsInSolution();
      var solutiondir = Path.GetDirectoryName(_dte2.Solution.FullName);

      // TODO
      ...

      var project = projects.FirstOrDefault(p => p.Name == <current project>);
      Console.WriteLine(project.FullName);
    }
  }

答案 22 :(得分:-7)

Directory.GetParent(Directory.GetCurrentDirectory())。Parent.Parent.Parent.Parent.FullName

将为您提供项目目录。