Wie erhalten Sie das aktuelle Projektverzeichnis aus C # -Code, wenn Sie eine benutzerdefinierte MSBuild-Aufgabe erstellen?

133

Anstatt ein externes Programm mit fest codiertem Pfad auszuführen, möchte ich das aktuelle Projektverzeichnis erhalten. Ich rufe ein externes Programm mit einem Prozess in der benutzerdefinierten Aufgabe auf.

Wie würde ich das machen? AppDomain.CurrentDomain.BaseDirectory gibt mir nur den Speicherort von VS 2008 an.

Sean
quelle

Antworten:

112

Sie können eine dieser beiden Methoden ausprobieren.

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

string startupPath = Environment.CurrentDirectory;

Sag mir, welches scheint dir besser zu sein

Iralda Mitro
quelle
85
Diese beiden oben genannten Punkte verweisen Sie auf das bin-Verzeichnis. Wenn Sie also beispielsweise ein bin-Verzeichnis für Ihre gesamte Lösung haben, verweist es Sie dort und NICHT auf Ihr Projektverzeichnis (oder zwei Ebenen UNTER Ihrem Projektverzeichnis)
matcheek
16
Beide Lösungen funktionieren bei Verwendung von Test Explorer nicht wie erwartet.
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;
Mohammed Sameeh
quelle
25
+1 für das Directory.GetParent (), damit wir das Verzeichnis \ bin \ Debug nicht erhalten :)
Eystein Bye
5
Was ist, wenn wir eine benutzerdefinierte Ziel-CPU verwenden? Wenn ich beispielsweise meinen Build auf Ziel x64 setze, wird ein weiterer Ordner dazwischen erstellt.
Samir Aguiar
3
Dies ist die richtige Antwort. Die akzeptierte Antwort gibt den Pfad zum bin-Verzeichnis zurück, das NICHT das Projektverzeichnis ist.
Pookie
@ pookies Antwort ist für meinen Fall rekursiv falsch. Dies gibt mir den Ordner * / {project} / bin, daher muss ich eine .parent-Datei speichern.
Captain Prinny
1
Funktioniert gut und dies sollte die akzeptierte Antwort sein
Ashok Kumar Ganesan
41

Wenn ein Projekt auf einem IIS Express ausgeführt wird, kann Environment.CurrentDirectorydies darauf verweisen, wo sich IIS Express befindet (der Standardpfad wäre C: \ Programme (x86) \ IIS Express ) und nicht darauf, wo sich Ihr Projekt befindet.


Dies ist wahrscheinlich der am besten geeignete Verzeichnispfad für verschiedene Arten von Projekten.

AppDomain.CurrentDomain.BaseDirectory

Dies ist die MSDN-Definition.

Ruft das Basisverzeichnis ab, mit dem der Assembly Resolver nach Assemblys sucht.

hina10531
quelle
20
9 Jahre später und jemand hat tatsächlich die richtige Antwort.
Jeff Davis
In .NET Core gibt es keine AppDomain. Sie müssten so etwas tun. System.Runtime.Loader.AssemblyLoadContext.Default.Unloading + = context => InvokeBatchProcessors ();
Latenz
Außerdem können Sie das Visual Studio SDK verwenden und den Speicherort mithilfe von DTE2 aus dem Lösungskonfigurationslayout abrufen.
Latenz
2
@ Latenz gibt es in einem .net Core 3 WPF-Projekt
Alexander
Ja, ich habe die Spezifikationen gelesen. Nichts wie 3,0 ist sicher. Ich benutze es seitdem. Sehr erfreut. Ich glaube, ich habe dieses Pre 3.0 gepostet, also danke für die Klarstellung.
Latenz
18

Dadurch erhalten Sie auch das Projektverzeichnis, indem Sie vom aktuellen Ausführungsverzeichnis aus zwei Ebenen nach oben navigieren (dies gibt nicht bei jedem Build das Projektverzeichnis zurück, dies ist jedoch das häufigste).

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

Natürlich möchten Sie dies in einer Art Validierungs- / Fehlerbehandlungslogik enthalten.

nh43de
quelle
IMO ist dies die flexibelste Methode. Ich verwende dies aus Unit-Tests und Integrationstests, wobei der Pfad tatsächlich tiefer in einem Ordner liegt.
Soleil - Mathieu Prévot
Dies gibt mir aus irgendeinem Grund das Root-Laufwerk.
Kapitän Prinny
10

Wenn Sie nicht wissen möchten, in welchem ​​Verzeichnis sich Ihre Lösung befindet, müssen Sie Folgendes tun:

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

Wenn Sie nur mit GetCurrrentDirectory()Methode zulassen , erhalten Sie den Build-Ordner, unabhängig davon, ob Sie debuggen oder freigeben. Ich hoffe diese Hilfe! Wenn Sie die Validierungen vergessen, sieht das folgendermaßen aus:

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

Ich habe auch danach gesucht. Ich habe ein Projekt, in dem HWC ausgeführt wird, und ich möchte die Website aus dem App-Baum heraushalten, aber ich möchte sie nicht im Debug- (oder Release-) Verzeichnis behalten. FWIW, die akzeptierte Lösung (und auch diese) identifiziert nur das Verzeichnis, in dem die ausführbare Datei ausgeführt wird.

Um dieses Verzeichnis zu finden, habe ich verwendet

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

Basierend auf der Antwort von Gucu112 , aber für .NET Core Console / Window-Anwendungen sollte es sein:

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

Ich verwende dies in einem xUnit-Projekt für eine .NET Core Window-Anwendung.

zwcloud
quelle
4

Ein anderer Weg, dies zu tun

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

Wenn Sie den Pfad zum Ordner bin erhalten möchten

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

Vielleicht gibt es einen besseren Weg =)

Tret
quelle
4

Noch eine unvollkommene Lösung (aber vielleicht ein bisschen näher an der Perfektion als einige der anderen):

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

Diese Version wird die Rückkehr aktuelle Projekte Ordner auch wenn das aktuelle Projekt nicht das ist Startup Projectfür die Lösung.

Der erste Fehler dabei ist, dass ich alle Fehlerprüfungen übersprungen habe. Dies kann leicht behoben werden, sollte jedoch nur dann ein Problem darstellen, wenn Sie Ihr Projekt im Stammverzeichnis des Laufwerks speichern oder eine Junction in Ihrem Pfad verwenden (und diese Junction ein Nachkomme des Lösungsordners ist), sodass dieses Szenario unwahrscheinlich ist . Ich bin mir nicht ganz sicher, ob Visual Studio eines dieser Setups überhaupt verarbeiten kann.

Ein weiteres (wahrscheinlicheres) Problem, auf das Sie möglicherweise stoßen, besteht darin, dass der Projektname mit dem Ordnernamen des Projekts übereinstimmen muss , damit es gefunden wird.

Ein weiteres Problem besteht möglicherweise darin, dass sich das Projekt im Lösungsordner befindet. Dies ist normalerweise kein Problem. Wenn Sie jedoch die Add Existing Project to SolutionOption zum Hinzufügen des Projekts zur Lösung verwendet haben, ist Ihre Lösung möglicherweise nicht so organisiert.

Wenn Ihre Anwendung das Arbeitsverzeichnis ändert, sollten Sie diesen Wert vorher speichern, da dieser Wert relativ zum aktuellen Arbeitsverzeichnis bestimmt wird.

Dies alles bedeutet natürlich auch, dass Sie die Standardwerte für die Optionen Build-> Output pathoder Debug-> Ihrer Projekte Working directoryim Dialogfeld Projekteigenschaften nicht ändern dürfen .

Krowe
quelle
4

Versuchen Sie dies, es ist einfach

HttpContext.Current.Server.MapPath("~/FolderName/");
Hardeep Singh
quelle
4

Diese Lösung funktioniert gut für mich, auf Develop- und auch auf TEST- und PROD-Servern mit ASP.NET MVC5 über C # :

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

Wenn Sie ein Projektverzeichnis in der Projektkonfigurationsdatei benötigen, verwenden Sie:

$(ProjectDir)
Jan Sršeň
quelle
3

Nachdem ich endlich meine erste Antwort bezüglich der Verwendung öffentlicher Zeichenfolgen poliert hatte, um eine Antwort abzuleiten, wurde mir klar, dass Sie wahrscheinlich einen Wert aus der Registrierung lesen konnten, um das gewünschte Ergebnis zu erzielen. Wie sich herausstellte, war diese Route noch kürzer:

Zunächst müssen Sie den Microsoft.Win32-Namespace angeben, damit Sie mit der Registrierung arbeiten können:

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

Hier ist der Hauptcode:

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

Ein Hinweis zu dieser Antwort:

Ich verwende Visual Studio 2008 Professional Edition. Wenn Sie eine andere Version verwenden (z. B. 2003, 2005, 2010; usw.), müssen Sie möglicherweise den 'version'-Teil der SubKey-Zeichenfolge (z. B. 8.0, 7.0; usw.) nicht ändern.

Wenn Sie eine meiner Antworten verwenden und es nicht zu viel verlangt, dann würde ich gerne wissen, welche meiner Methoden Sie verwendet haben und warum. Viel Glück.

  • dm
Digitalmythologie
quelle
3

Ich hatte eine ähnliche Situation und nach fruchtlosen Googles habe ich eine öffentliche Zeichenfolge deklariert, die einen Zeichenfolgenwert des Debug- / Release-Pfads ändert, um den Projektpfad abzurufen. Ein Vorteil dieser Methode besteht darin, dass es nicht darauf ankommt, ob Sie von einem Debug-Verzeichnis oder einem Release-Verzeichnis aus arbeiten, da sie das Verzeichnis des korrekten Projekts verwendet:

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

Sie können es dann jederzeit mit nur einer Leitung aufrufen:

string MyProjectDir = DirProject();

Dies sollte in den meisten Fällen funktionieren .

Digitalmythologie
quelle
3

Verwenden Sie dies, um das Projektverzeichnis abzurufen (für mich gearbeitet):

string projectPath = 
    Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;
user5219877
quelle
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
quelle
2

Ich habe folgende Lösung verwendet, um die Arbeit zu erledigen:

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

Versuchen:

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

Diese Lösung unterscheidet sich von den anderen und berücksichtigt auch mögliche x86- oder x64-Builds.

David Desmaisons
quelle
Diese Lösung ist fast auch für die neuen csproj-Dateien verfügbar, in denen das TargetFramework im Pfad enthalten ist.
Glenn Watson
1
Für das neue .netcore-Format hatte ich neues Regex (@ "\\ bin (\\ x86 | \\ x64)? \ (Debug | Release) (\ [a-zA-Z0-9.] *)? $" , RegexOptions.Compiled)
Glenn Watson
1

Die beste Lösung

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

Andere Lösung

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

Testen Sie es, AppDomain.CurrentDomain.BaseDirectory hat für mich an einem früheren Projekt gearbeitet, jetzt erhalte ich einen Debug-Ordner .... die ausgewählte GUTE Antwort funktioniert einfach NICHT!.

//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
quelle
0

Wenn Sie wirklich sicherstellen möchten, dass Sie das Quellprojektverzeichnis erhalten, unabhängig davon, auf welchen Bin-Ausgabepfad festgelegt ist:

  1. Fügen Sie eine Befehlszeile für Ereignisse vor dem Erstellen hinzu (Visual Studio: Projekteigenschaften -> Ereignisse erstellen):

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

  2. Fügen Sie die ProjectDirectory.txtDatei zur Datei Resources.resx des Projekts hinzu (Wenn sie noch nicht vorhanden ist, klicken Sie mit der rechten Maustaste auf Projekt -> Neues Element hinzufügen -> Ressourcendatei.)

  3. Zugriff vom Code mit Resources.ProjectDirectory.
FunctorSalad
quelle
-1

Dies funktioniert bei VS2017 mit SDK Core MSBuild-Konfigurationen.

Sie müssen NuGet in den EnvDTE / EnvDTE80-Paketen verwenden.

Verwenden Sie weder COM noch Interop. alles .... Müll !!

 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);
    }
  }
Latenz
quelle
-6

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

Gibt Ihnen das Projektverzeichnis.

brian kitcehner
quelle
77
Ja wirklich? Ich denke, Sie vermissen einen Elternteil
Sean