Comment obtenir le répertoire de projet actuel à partir du code C # lors de la création d'une tâche MSBuild personnalisée?


133

Au lieu d'exécuter un programme externe avec son chemin d'accès codé en dur, j'aimerais obtenir le Dir de projet actuel. J'appelle un programme externe en utilisant un processus dans la tâche personnalisée.

Comment pourrais-je faire ça? AppDomain.CurrentDomain.BaseDirectory me donne juste l'emplacement de VS 2008.

Réponses:


112

Vous pouvez essayer l'une de ces deux méthodes.

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

string startupPath = Environment.CurrentDirectory;

Dites-moi lequel vous semble le mieux


85
Ces deux ci-dessus vous dirigent vers le répertoire bin, donc si vous avez par exemple un répertoire bin pour toute votre solution, il vous y dirigera et PAS vers votre répertoire de projet (ou deux niveaux AU-DESSOUS de votre répertoire de projet)
matcheek

16
Les deux solutions ne fonctionneront pas comme prévu lors de l'utilisation de l'Explorateur de tests.
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 pour le Directory.GetParent () donc nous n'obtenons pas le répertoire \ bin \ Debug :)
Eystein Bye

5
Et si nous utilisons un processeur cible personnalisé? Par exemple, si je configure ma build pour cibler x64, il crée un autre dossier entre ceux-ci.
Samir Aguiar

3
C'est la bonne réponse. La réponse acceptée renvoie le chemin du répertoire bin, qui n'est PAS le répertoire du projet.
pookie

La réponse de @ pookie est récursivement fausse pour mon cas. Cela me donne le dossier * / {project} / bin, donc j'ai besoin de concaténer un .parent.
Captain Prinny

1
Fonctionne bien et cela devrait être la réponse acceptée
Ashok kumar Ganesan

42

Si un projet s'exécute sur un IIS Express, le Environment.CurrentDirectorypeut pointer vers l'emplacement d'IIS Express (le chemin d'accès par défaut serait C: \ Program Files (x86) \ IIS Express ), pas vers l'emplacement de votre projet.


C'est probablement le chemin de répertoire le plus approprié pour différents types de projets.

AppDomain.CurrentDomain.BaseDirectory

C'est la définition MSDN.

Obtient le répertoire de base que le résolveur d'assembly utilise pour rechercher les assemblys.


21
9 ans plus tard, quelqu'un a la vraie réponse.
Jeff Davis

Il n'y a pas AppDomain dans .NET Core. Il faudrait faire quelque chose comme ça. System.Runtime.Loader.AssemblyLoadContext.Default.Unloading + = context => InvokeBatchProcessors ();
Latence du

En outre, vous pouvez utiliser le SDK Visual Studio et obtenir l'emplacement à partir de la disposition de configuration de la solution à l'aide de DTE2.
Latence du

2
@Latency il y a dans un projet WPF .net core 3
Alexander

Ouais, j'ai lu les spécifications. Rien de tel que 3,0 c'est sûr. Je l'utilise depuis. Très content. Je pense que j'ai posté ce pré 3.0 alors merci pour la clarification.
Latence du

18

Cela vous donnera également le répertoire du projet en naviguant de deux niveaux vers le haut à partir du répertoire d'exécution actuel (cela ne retournera pas le répertoire du projet pour chaque build, mais c'est le plus courant).

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

Bien sûr, vous voudriez contenir cela dans une sorte de logique de validation / gestion des erreurs.


IMO c'est la méthode la plus flexible. J'utilise cela à partir de tests unitaires et de tests d'intégration, dont le chemin est en fait plus profond d'un dossier.
Soleil - Mathieu Prévot

Cela me donne le lecteur racine pour une raison quelconque.
Captain Prinny

10

Si vous voulez savoir quel est le répertoire où se trouve votre solution, vous devez faire ceci:

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

Si vous ne laissez qu'avec la GetCurrrentDirectory()méthode, vous obtenez le dossier de construction, peu importe si vous déboguez ou publiez. J'espère que cette aide! Si vous oubliez les validations, ce serait comme ceci:

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

5

Je cherchais ça aussi. J'ai un projet qui exécute HWC, et j'aimerais garder le site Web hors de l'arborescence des applications, mais je ne veux pas le garder dans le répertoire de débogage (ou de publication). FWIW, la solution acceptée (et celle-ci également) identifie uniquement le répertoire dans lequel s'exécute l'exécutable.

Pour trouver ce répertoire, j'ai utilisé

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

5

Basé sur la réponse de Gucu112 , mais pour l'application .NET Core Console / Window, cela devrait être:

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

J'utilise ceci dans un projet xUnit pour une application Windows .NET Core.


4

Une autre façon de faire cela

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

Si vous souhaitez obtenir le chemin du dossier bin

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

Peut-être qu'il y a un meilleur moyen =)


4

Encore une autre solution imparfaite (mais peut-être un peu plus proche de la perfection que certaines des autres):

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

Cette version renverra le dossier des projets en cours même si le projet en cours n'est pas leStartup Project pour la solution.

Le premier défaut avec ceci est que j'ai ignoré toutes les vérifications d'erreurs. Cela peut être résolu assez facilement mais ne devrait être un problème que si vous stockez votre projet dans le répertoire racine du lecteur ou si vous utilisez une jonction dans votre chemin (et cette jonction est un descendant du dossier de solution) donc ce scénario est peu probable . Je ne suis pas tout à fait sûr que Visual Studio puisse gérer l'une de ces configurations de toute façon.

Un autre problème (plus probable) que vous pouvez rencontrer est que le nom du projet doit correspondre au nom du dossier du projet pour qu'il soit trouvé.

Un autre problème que vous pouvez rencontrer est que le projet doit se trouver dans le dossier de solution. Ce n'est généralement pas un problème, mais si vous avez utilisé l' Add Existing Project to Solutionoption pour ajouter le projet à la solution, cela peut ne pas être la façon dont votre solution est organisée.

Enfin, si votre application modifie le répertoire de travail, vous devez stocker cette valeur avant de le faire car cette valeur est déterminée par rapport au répertoire de travail actuel.

Bien sûr, tout cela signifie également que vous ne devez pas modifier les valeurs par défaut des options Build-> Output pathou Debug-> de vos projets Working directorydans la boîte de dialogue des propriétés du projet.


4

Essayez ceci, c'est simple

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

4

Cette solution fonctionne bien pour moi, sur Develop mais aussi sur les serveurs TEST et PROD avec ASP.NET MVC5 via C # :

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

Si vous avez besoin du répertoire du projet dans le fichier de configuration du projet, utilisez:

$(ProjectDir)

3

Après avoir finalement fini de peaufiner ma première réponse concernant l'utilisation des chaînes publiques pour obtenir une réponse, je me suis rendu compte que vous pouviez probablement lire une valeur du registre pour obtenir le résultat souhaité. En fait, cet itinéraire était encore plus court:

Tout d'abord, vous devez inclure l'espace de noms Microsoft.Win32 afin de pouvoir travailler avec le registre:

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

Voici le code principal:

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

Une note sur cette réponse:

J'utilise Visual Studio 2008 Professional Edition. Si vous utilisez une autre version (par exemple, 2003, 2005, 2010, etc.), vous n'aurez peut-être pas à modifier la partie «version» de la chaîne de sous-clé (par exemple, 8.0, 7.0; etc.).

Si vous utilisez l'une de mes réponses, et si ce n'est pas trop demander, alors j'aimerais savoir laquelle de mes méthodes vous avez utilisée et pourquoi. Bonne chance.

  • dm

3

J'ai eu une situation similaire, et après des Googles infructueux, j'ai déclaré une chaîne publique, qui modifie une valeur de chaîne du chemin de débogage / de publication pour obtenir le chemin du projet. Un avantage de l'utilisation de cette méthode est que puisqu'elle utilise le répertoire du projet currect, peu importe si vous travaillez à partir d'un répertoire de débogage ou d'un répertoire de version:

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

Vous pourrez alors l'appeler quand vous le souhaitez, en utilisant une seule ligne:

string MyProjectDir = DirProject();

Cela devrait fonctionner dans la plupart des cas.


3

Utilisez ceci pour obtenir le répertoire du projet (a fonctionné pour moi):

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

J'ai utilisé la solution suivante pour faire le travail:

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

2

Essayer:

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

Cette solution différente des autres prend également en compte une éventuelle build x86 ou x64.


Cette solution est presque là pour les nouveaux fichiers csproj où le TargetFramework est inclus dans le chemin.
Glenn Watson

1
Pour le nouveau format de style .netcore, j'avais un nouveau Regex (@ "\\ bin (\\ x86 | \\ x64)? \ (Debug | Release) (\ [a-zA-Z0-9.] *)? $" , RegexOptions.Compiled)
Glenn Watson

1

La meilleure solution

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

Autre solution

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

Testez-le, AppDomain.CurrentDomain.BaseDirectory a travaillé pour moi sur le projet précédent, maintenant je reçois le dossier de débogage .... la BONNE réponse sélectionnée ne fonctionne tout simplement pas !.

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

Si vous voulez vraiment vous assurer d'obtenir le répertoire du projet source, quel que soit le chemin de sortie du bac:

  1. Ajoutez une ligne de commande d'événement de pré-génération (Visual Studio: Propriétés du projet -> Événements de génération):

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

  2. Ajoutez le ProjectDirectory.txtfichier au Resources.resx du projet (s'il n'existe pas encore, faites un clic droit sur projet -> Ajouter un nouvel élément -> Fichier de ressources)

  3. Accès à partir du code avec Resources.ProjectDirectory.

-1

Cela fonctionne sur les configurations VS2017 avec SDK Core MSBuild.

Vous devez utiliser NuGet dans les packages EnvDTE / EnvDTE80.

N'utilisez pas COM ou Interop. rien ... des ordures !!

 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

Vous donnera le répertoire du projet.


77
vraiment? Je pense que vous manquez un parent
sean
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.