Jak uzyskać bieżący katalog projektu z kodu C # podczas tworzenia niestandardowego zadania MSBuild?

142

Zamiast uruchamiać zewnętrzny program z zakodowaną na stałe ścieżką, chciałbym uzyskać bieżący Project Dir. Wywołuję program zewnętrzny przy użyciu procesu w zadaniu niestandardowym.

Jak miałbym to zrobić? AppDomain.CurrentDomain.BaseDirectory podaje mi tylko lokalizację VS 2008.

Sean
źródło

Odpowiedzi:

118

Możesz wypróbować jedną z tych dwóch metod.

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

string startupPath = Environment.CurrentDirectory;

Powiedz mi, który wydaje ci się lepszy

Iralda Mitro
źródło
92
Te dwa powyższe kierują Cię do katalogu bin, więc jeśli masz na przykład jeden katalog bin dla całego rozwiązania, wskaże cię tam, a NIE katalog twojego projektu (lub dwa poziomy PONIŻEJ katalogu twojego projektu)
mecz
17
Oba rozwiązania nie będą działać zgodnie z oczekiwaniami podczas korzystania z Eksploratora testów.
Gucu112
281
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 bin directory (ie ../bin/)
string projectDirectory = Directory.GetParent(workingDirectory).Parent.FullName;

// This will get the current PROJECT directory
string projectDirectory = Directory.GetParent(workingDirectory).Parent.Parent.FullName;
mohammed sameeh
źródło
26
+1 dla Directory.GetParent (), więc nie otrzymujemy katalogu \ bin \ Debug :)
Eystein Bye
6
A co, jeśli użyjemy niestandardowego docelowego procesora? Na przykład, jeśli ustawię moją kompilację na docelowy x64, utworzy między nimi inny folder.
Samir Aguiar
4
To jest poprawna odpowiedź. Zaakceptowana odpowiedź zwraca ścieżkę do katalogu bin, który NIE jest katalogiem projektu.
pookie
1
Odpowiedź @ pookie jest rekursywnie błędna w moim przypadku. To daje mi folder * / {projekt} / bin, więc muszę połączyć .parent.
Kapitan Prinny
2
Działa dobrze i to powinna być akceptowana odpowiedź
Ashok kumar Ganesan
47

Jeśli projekt jest uruchomiony w programie IIS Express, Environment.CurrentDirectorymoże wskazywać lokalizację IIS Express (domyślna ścieżka to C: \ Program Files (x86) \ IIS Express ), a nie miejsce, w którym znajduje się projekt.


Jest to prawdopodobnie najbardziej odpowiednia ścieżka do katalogu dla różnych rodzajów projektów.

AppDomain.CurrentDomain.BaseDirectory

To jest definicja MSDN.

Pobiera katalog podstawowy, którego program rozpoznawania zestawu używa do sondowania dla zestawów.

hina10531
źródło
23
9 lat później ktoś rzeczywiście ma prawdziwą odpowiedź.
Jeff Davis,
NET Core nie ma domeny AppDomain. Musiałbyś zrobić coś takiego. System.Runtime.Loader.AssemblyLoadContext.Default.Unloading + = context => InvokeBatchProcessors ();
Opóźnienie
Poza tym możesz użyć Visual Studio SDK i pobrać lokalizację z układu konfiguracji rozwiązania przy użyciu DTE2.
Opóźnienie
2
@Latency istnieje w projekcie WPF .net core 3
Alexander,
Tak, przeczytałem specyfikację. Nic takiego jak 3,0 to na pewno. Od tamtej pory go używam. Bardzo zadowolony. Myślę, że opublikowałem to przed 3.0, więc dziękuję za wyjaśnienie.
Opóźnienie
18

Zapewni to również katalog projektu, przechodząc o dwa poziomy w górę z bieżącego katalogu wykonywania (nie zwróci to katalogu projektu dla każdej kompilacji, ale jest to najbardziej typowe).

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

Oczywiście chciałbyś zawrzeć to w jakiejś logice walidacji / obsługi błędów.

nh43de
źródło
IMO to najbardziej elastyczna metoda. Używam tego z testów jednostkowych i testów integracji, których ścieżka jest w rzeczywistości głębsza od jednego folderu.
Soleil - Mathieu Prévot
To daje mi dysk roota z jakiegoś powodu.
Kapitan Prinny
11

Jeśli chcesz wiedzieć, jaki jest katalog, w którym znajduje się Twoje rozwiązanie, musisz to zrobić:

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

Jeśli pozwolisz tylko przy użyciu GetCurrrentDirectory()metody, otrzymasz folder kompilacji bez względu na to, czy debugujesz, czy zwalniasz. Mam nadzieję, że ta pomoc! Jeśli zapomnisz o walidacjach, będzie tak:

var startDirectory = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName;
abel406
źródło
7

Na podstawie odpowiedzi Gucu112 , ale dla aplikacji .NET Core Console / Window powinno to być:

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

Używam tego w projekcie xUnit dla aplikacji .NET Core Window.

zwcloud
źródło
6

To rozwiązanie działa dobrze dla mnie, na Develop, a także na serwerach TEST i PROD z ASP.NET MVC5 przez C # :

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

Jeśli potrzebujesz katalogu projektu w pliku konfiguracyjnym projektu, użyj:

$(ProjectDir)
Jan Sršeň
źródło
5

Ja też tego szukałem. Mam projekt, w którym działa HWC i chciałbym, aby witryna sieci Web nie znajdowała się w drzewie aplikacji, ale nie chcę jej przechowywać w katalogu debugowania (lub wydania). FWIW, zaakceptowane rozwiązanie (i to również) identyfikuje tylko katalog, w którym działa plik wykonywalny.

Aby znaleźć ten katalog, użyłem

string startupPath = System.IO.Path.GetFullPath(".\\").
Brett
źródło
4

Miałem podobną sytuację i po bezowocnych Googles zadeklarowałem publiczny ciąg znaków, który modyfikuje wartość ciągu ścieżki debugowania / wydania, aby uzyskać ścieżkę projektu. Zaletą korzystania z tej metody jest to, że ponieważ używa ona katalogu bieżącego projektu, nie ma znaczenia, jeśli pracujesz z katalogu debugowania lub katalogu wydania:

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

Możesz wtedy zadzwonić, kiedy tylko chcesz, używając tylko jednej linii:

string MyProjectDir = DirProject();

To powinno działać w większości przypadków.

cyfrowa mitologia
źródło
To działa dobrze, dziękuję
VishnuKumar ps
4

Inny sposób, aby to zrobić

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

Jeśli chcesz uzyskać ścieżkę do folderu bin

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

Może jest lepszy sposób =)

Tret
źródło
4

Jeszcze jedno niedoskonałe rozwiązanie (ale być może trochę bliższe doskonałemu niż niektóre inne):

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

Ta wersja zwróci folder bieżących projektów, nawet jeśli bieżący projekt nie jest Startup Projectprzeznaczony dla rozwiązania.

Pierwsza wada polega na tym, że pominąłem wszystkie sprawdzanie błędów. Można to naprawić dość łatwo, ale powinno to stanowić problem tylko wtedy, gdy przechowujesz projekt w katalogu głównym dysku lub używasz skrzyżowania w ścieżce (i to skrzyżowanie jest elementem podrzędnym folderu rozwiązania), więc ten scenariusz jest mało prawdopodobny . Nie jestem do końca pewien, czy Visual Studio i tak poradzi sobie z którąkolwiek z tych konfiguracji.

Innym (bardziej prawdopodobnym) problemem, na który możesz się natknąć, jest to, że nazwa projektu musi być zgodna z nazwą folderu projektu, aby można go było znaleźć.

Innym problemem, który możesz mieć, jest to, że projekt musi znajdować się w folderze rozwiązania. Zwykle nie stanowi to problemu, ale jeśli użyłeś Add Existing Project to Solutionopcji dodania projektu do rozwiązania, może to nie być sposób zorganizowania rozwiązania.

Na koniec, jeśli twoja aplikacja będzie modyfikować katalog roboczy, powinieneś zapisać tę wartość zanim to zrobisz, ponieważ ta wartość jest określana względem bieżącego katalogu roboczego.

Oczywiście to wszystko oznacza również, że nie możesz zmieniać domyślnych wartości opcji Build-> Output pathlub Debug-> Working directoryprojektów w oknie dialogowym właściwości projektu.

krowe
źródło
4

Spróbuj tego, to proste

HttpContext.Current.Server.MapPath("~/FolderName/");
Hardeep Singh
źródło
3

Kiedy w końcu skończyłem szlifować moją pierwszą odpowiedź dotyczącą nas z publicznych ciągów znaków, aby uzyskać odpowiedź, dotarło do mnie, że prawdopodobnie możesz odczytać wartość z rejestru, aby uzyskać pożądany rezultat. Jak się okazuje, ta trasa była jeszcze krótsza:

Po pierwsze, musisz dołączyć przestrzeń nazw Microsoft.Win32, aby móc pracować z rejestrem:

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

Oto główny kod:

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

Uwaga dotycząca tej odpowiedzi:

Używam Visual Studio 2008 Professional Edition. Jeśli używasz innej wersji (np. 2003, 2005, 2010 itp.), Może być konieczne zmodyfikowanie części „wersja” ciągu SubKey (np. 8.0, 7.0 itp.).

Jeśli skorzystasz z jednej z moich odpowiedzi i jeśli nie jest to zbyt wiele pytań, to chciałbym wiedzieć, której z moich metod użyłeś i dlaczego. Powodzenia.

  • dm
cyfrowa mitologia
źródło
3

Użyj tego, aby uzyskać katalog projektu (pracował dla mnie):

string projectPath = 
    Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;
user5219877
źródło
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;
JeffreyYe_THU
źródło
2

Do wykonania pracy użyłem następującego rozwiązania:

string projectDir =
    Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\.."));
Gucu112
źródło
2

Próbować:

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

To rozwiązanie różni się od innych i uwzględnia również możliwą kompilację x86 lub x64.

David Desmaisons
źródło
To rozwiązanie jest już prawie dostępne dla nowych plików csproj, w których ścieżka TargetFramework jest uwzględniona.
Glenn Watson
1
Dla nowego formatu stylu .netcore miałem nowy Regex (@ "\\ bin (\\ x86 | \\ x64)? \ (Debug | Release) (\ [a-zA-Z0-9.] *)? $" , RegexOptions.Compiled)
Glenn Watson
2

Jeśli naprawdę chcesz mieć pewność, że otrzymasz katalog źródłowy projektu, bez względu na to, jaka ścieżka wyjściowa bin jest ustawiona na:

  1. Dodaj wiersz polecenia zdarzenia przed kompilacją (Visual Studio: właściwości projektu -> zdarzenia kompilacji): Add a pre-build event command line (Visual Studio: Project properties -> Build Events):

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

  2. Dodaj ProjectDirectory.txtplik do Resources.resx projektu (jeśli jeszcze nie istnieje, kliknij prawym przyciskiem myszy projekt -> Dodaj nowy element -> Plik zasobów)

  3. Dostęp z kodu za pomocą Resources.ProjectDirectory.
FunctorSalad
źródło
1
To jedyna dobra odpowiedź. Ponieważ korzystałem z katalogu do testów jednostkowych, zrobiłem to: echo $ (ProjectDir)> $ (ProjectDir) \ Input \ ProjectDir.txt I dołączyłem ProjectDir.txt jako element wdrażania testów jednostkowych. Bez względu na to, gdzie są uruchamiane testy, mam teraz folder kompilacji.
Ed Bayiates
1

Najlepszym rozwiązaniem

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

Inne rozwiązanie

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

Przetestuj, AppDomain.CurrentDomain.BaseDirectory pracował dla mnie w poprzednim projekcie, teraz otrzymuję folder debugowania .... wybrana DOBRA odpowiedź po prostu NIE DZIAŁA !.

//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
Eduardo Chávez
źródło
0

Działa to w konfiguracjach VS2017 w / SDK Core MSBuild.

Musisz NuGet w pakietach EnvDTE / EnvDTE80.

Nie używaj COM ani międzyoperacyjności. cokolwiek .... śmieci !!

 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);
    }
  }
Czas oczekiwania
źródło
-5

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

Da ci katalog projektu.

brian kitcehner
źródło
80
naprawdę? Myślę, że brakuje ci rodzica
sean