Как получить текущий каталог проекта из кода C # при создании настраиваемой задачи MSBuild?


133

Вместо того, чтобы запускать внешнюю программу с жестко заданным путем, я хотел бы получить текущий каталог проекта. Я вызываю внешнюю программу, используя процесс в настраиваемой задаче.

Как бы я это сделал? AppDomain.CurrentDomain.BaseDirectory просто дает мне местоположение VS 2008.

Ответы:


112

Вы можете попробовать один из этих двух методов.

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

string startupPath = Environment.CurrentDirectory;

Скажите, какой вам кажется лучше


85
Эти два приведенных выше указывают на каталог bin, поэтому, если у вас есть, например, один каталог bin для всего решения, он укажет вам именно туда, а НЕ в каталог вашего проекта (или на два уровня НИЖЕ каталога вашего проекта)
matcheek

16
Оба решения не будут работать должным образом при использовании обозревателя тестов.
Gucu112

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 :)
Эйстейн Пока

5
Что, если мы будем использовать настраиваемый целевой ЦП? Например, если я установил свою сборку для целевой x64, она создаст другую папку между ними.
Samir Aguiar

3
Это правильный ответ. Принятый ответ возвращает путь к каталогу bin, который НЕ является каталогом проекта.
pookie

Ответ @pookie рекурсивно неверен для моего случая. Это дает мне папку * / {project} / bin, поэтому мне нужно объединить .parent.
Captain Prinny

1
Работает хорошо, и это должен быть принятый ответ
Ашок Кумар Ганесан

42

Если проект выполняется в IIS Express, он Environment.CurrentDirectoryможет указывать на то, где находится IIS Express (путь по умолчанию - C: \ Program Files (x86) \ IIS Express ), а не на то, где находится ваш проект.


Вероятно, это наиболее подходящий путь к каталогу для различных проектов.

AppDomain.CurrentDomain.BaseDirectory

Это определение MSDN.

Получает базовый каталог, который распознаватель сборок использует для поиска сборок.


21
9 лет спустя, и у кого-то есть настоящий ответ.
Джефф Дэвис

В .NET Core нет AppDomain. Вам нужно будет сделать что-то подобное. System.Runtime.Loader.AssemblyLoadContext.Default.Unloading + = context => InvokeBatchProcessors ();
Задержка

Кроме того, вы можете использовать Visual Studio SDK и получить местоположение из макета конфигурации решения с помощью DTE2.
Задержка

2
@Latency есть в проекте WPF .net core 3
Александр

Да, я читал спецификации. Ничего подобного 3,0 точно нет. Пользуюсь им с тех пор. Очень доволен. Я думаю, что опубликовал эту версию до 3.0, поэтому спасибо за разъяснения.
Задержка

18

Это также даст вам каталог проекта, перейдя на два уровня вверх от текущего каталога выполнения (это не будет возвращать каталог проекта для каждой сборки, но это наиболее распространенный вариант).

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

Конечно, вы хотели бы поместить это в какую-то логику проверки / обработки ошибок.


IMO это самый гибкий метод. Я использую это из модульных тестов и интеграционных тестов, путь которых на самом деле глубже одной папки.
Soleil - Матье Прево

По какой-то причине это дает мне корневой диск.
Капитан Принни

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()методом, вы получите папку сборки независимо от того, отлаживаете ли вы или выпускаете. Надеюсь, это поможет! Если вы забудете о валидациях, это будет примерно так:

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

5

Я тоже это искал. У меня есть проект, в котором работает HWC, и я бы хотел, чтобы этот веб-сайт не входил в дерево приложений, но я не хочу оставлять его в каталоге отладки (или выпуска). FWIW, принятое решение (и это тоже) определяет только каталог, в котором выполняется исполняемый файл.

Чтобы найти этот каталог, я использовал

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

5

На основе ответа Gucu112 , но для приложения .NET Core Console / Window это должно быть:

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 pathили Debug-> Working directoryпараметры в диалоговом окне свойств проекта.



4

Это решение хорошо работает для меня на Develop, а также на серверах TEST и PROD с ASP.NET MVC5 через C # :

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 Professional Edition. Если вы используете другую версию (например, 2003, 2005, 2010 и т. Д.), Возможно, вам не придется изменять часть «версия» в строке SubKey (например, 8.0, 7.0 и т. Д.).

Если вы воспользуетесь одним из моих ответов, и если это не слишком много вопросов, то я хотел бы знать, какой из моих методов вы использовали и почему. Удачи.

  • дм

3

У меня была аналогичная ситуация, и после бесплодных поисков в Google я объявил публичную строку, которая изменяет строковое значение пути отладки / выпуска, чтобы получить путь к проекту. Преимущество использования этого метода заключается в том, что, поскольку он использует каталог текущего проекта, не имеет значения, работаете ли вы из каталога отладки или каталога выпуска:

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

Используйте это, чтобы получить каталог проекта (работал у меня):

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

Это работает с конфигурациями VS2017 с SDK Core MSBuild.

Вам необходимо NuGet в пакетах EnvDTE / EnvDTE80.

Не используйте 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);
    }
  }

-6

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

Вы получите каталог проекта.


77
действительно? Я думаю, ты скучаешь по Родителю,
Шон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.