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


133

我不想运行带有路径硬编码的外部程序,而是要获取当前的Project Dir。我正在使用自定义任务中的进程来调用外部程序。

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

Answers:


112

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

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

string startupPath = Environment.CurrentDirectory;

告诉我,哪个更适合您


85
上面的这两个指向您指向bin目录,因此,例如,如果您有一个用于整个解决方案的bin目录,它将指向您那里,而不是您的项目目录(或项目目录下的两个级别)
matcheek 2012年

16
使用测试资源管理器时,两种解决方案均无法正常工作。
Gucu112 '18

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

25
+1为Directory.GetParent(),所以我们没有得到\ bin \ Debug目录:)
Eystein Bye 2012年

5
如果我们使用自定义目标CPU怎么办?例如,如果我将构建设置为目标x64,它将在两者之间创建另一个文件夹。
萨米尔·阿吉亚尔

3
这是正确的答案。接受的答案返回到bin目录的路径,该目录不是项目目录。
pookie

对于我的情况,@ pookie的答案是递归错误的。这给了我* / {project} / bin文件夹,所以我需要连接一个.parent。
普林尼船长

1
工作正常,这应该是公认的答案
Ashok kumar Ganesan

41

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


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

AppDomain.CurrentDomain.BaseDirectory

这是MSDN定义。

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


20
9年后,实际上有一个真正的答案。
杰夫·戴维斯

.NET Core中没有AppDomain。您将必须执行以下操作。System.Runtime.Loader.AssemblyLoadContext.Default.Unloading + =上下文=> InvokeBatchProcessors();
延迟

除此之外,您还可以使用Visual Studio SDK,并使用DTE2从解决方案配置布局中获取位置。
延迟

2
@Latency在.net核心3 WPF项目中
亚历山大

是的,我阅读了规格。肯定不是3,0。从那以后我一直在使用它。很高兴。我想我发布了3.0之前的版本,因此感谢您的澄清。
延迟

18

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

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

当然,您可能希望将其包含在某种验证/错误处理逻辑中。


IMO这是最灵活的方法。我正在单元测试和集成测试中使用它,该路径实际上比一个文件夹更深。
Soleil-MathieuPrévot18年

由于某种原因,这给了我根驱动器。
普林尼船长,

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

如果只使用GetCurrrentDirectory()method,则无论调试还是发布,都将获得build文件夹。希望对您有所帮助!如果您忘记验证,它将是这样的:

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

5

我也在寻找这个。我有一个运行HWC的项目,但我想将该网站保留在应用程序树之外,但我不想将其保留在debug(或发布)目录中。FWIW,公认的解决方案(以及该解决方案)仅标识可执行文件正在运行的目录。

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

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

5

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

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

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


4

另一种方式

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

如果要获取bin文件夹的路径

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

也许有更好的方法=)


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选项的默认值。



4

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

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

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

$(ProjectDir)

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

3

我遇到过类似的情况,在Google毫无成果之后,我声明了一个公共字符串,该字符串修改了debug / release路径的字符串值以获取项目路径。使用此方法的好处是,由于它使用当前项目的目录,因此无论是从调试目录还是从发布目录进行操作,都无关紧要:

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

大多数情况下,这应该可行。


3

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

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

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

2

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

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

2

尝试:

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

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


对于新的csproj文件,几乎也存在该解决方案,其中路径中包含TargetFramework。
格伦·沃森

1
对于新的.netcore样式格式,我有新的Regex(@“ \\ bin(\\ x86 | \\ x64)?\(Debug | Release)(\ [a-zA-Z0-9。] *)?$” ,RegexOptions.Compiled)
格伦·沃森

1

最好的解决方案

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

0

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

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

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

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

  3. 从代码访问 Resources.ProjectDirectory

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.