Como você obtém o diretório de projeto atual do código C # ao criar uma tarefa personalizada do MSBuild?

133

Em vez de executar um programa externo com seu caminho codificado, eu gostaria de obter o Dir atual do projeto. Estou chamando um programa externo usando um processo na tarefa personalizada.

Como eu faria isso? AppDomain.CurrentDomain.BaseDirectory apenas fornece a localização do VS 2008.

sean
fonte

Respostas:

112

Você pode tentar um desses dois métodos.

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

string startupPath = Environment.CurrentDirectory;

Diga-me, qual deles lhe parece melhor

Iralda Mitro
fonte
85
Estes dois pontos acima você para o diretório bin, então se você tem por exemplo um diretório bin para toda sua solução que irá apontar lá e não para o diretório do projeto (ou dois níveis abaixo do seu diretório do projeto)
matcheek
16
Ambas as soluções não funcionarão conforme o esperado ao usar o Test Explorer.
precisa saber é o seguinte
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
fonte
25
+1 para o Directory.GetParent (), de modo que nós não obter o \ bin \ Debug :)
Eystein Bye
5
E se usarmos uma CPU de destino personalizada? Por exemplo, se eu definir meu build para o destino x64, ele criará outra pasta entre eles.
Samir Aguiar
3
Essa é a resposta correta. A resposta aceita retorna o caminho para o diretório bin, que NÃO é o diretório do projeto.
Pookie
A resposta de @ pookie está recursivamente errada para o meu caso. Isso está me dando a pasta * / {project} / bin, então preciso concatenar um .parent.
Capitão Prinny de
1
Trabalhar bem e esta deve ser a resposta aceita
Ashok Kumar Ganesan
42

Se um projeto estiver sendo executado em um IIS Express, Environment.CurrentDirectorypoderá apontar para onde o IIS Express está localizado (o caminho padrão seria C: \ Arquivos de Programas (x86) \ IIS Express ), e não para onde o seu projeto reside.


Este é provavelmente o caminho de diretório mais adequado para vários tipos de projetos.

AppDomain.CurrentDomain.BaseDirectory

Esta é a definição do MSDN.

Obtém o diretório base que o resolvedor de montagem usa para investigar montagens.

hina10531
fonte
21
9 anos depois e alguém realmente tem a resposta real.
21418 Jeff Jeff
Não há AppDomain no .NET Core. Você teria que fazer algo assim. System.Runtime.Loader.AssemblyLoadContext.Default.Unloading + = context => InvokeBatchProcessors ();
Latency
Além disso, você pode usar o SDK do Visual Studio e obter o local no layout de configuração da solução usando o DTE2.
Latency
2
@Latency existe em um projeto de núcleo .net 3 WPF
Alexander
Sim, eu li as especificações. Nada como 3,0, com certeza. Eu tenho usado desde então. Muito satisfeito. Acho que publiquei este pre 3.0, então obrigado pelo esclarecimento.
Latência
18

Isso também fornecerá o diretório do projeto, navegando dois níveis acima do diretório em execução atual (isso não retornará o diretório do projeto para cada construção, mas é o mais comum).

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

É claro que você gostaria de conter isso dentro de algum tipo de lógica de validação / tratamento de erros.

nh43de
fonte
IMO, este é o método mais flexível. Estou usando isso de testes de unidade e testes de integração, cujo caminho é realmente mais profundo de uma pasta.
Soleil - Mathieu Pré-
Isso está me dando a unidade raiz por algum motivo.
Capitão Prinny
10

Se você quiser saber qual é o diretório em que sua solução está localizada, faça o seguinte:

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

Se você deixar apenas o GetCurrrentDirectory()método, obterá a pasta de compilação, independentemente de estar depurando ou liberando. Espero que isso ajude! Se você esquecer as validações, seria assim:

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

Eu também estava procurando por isso. Eu tenho um projeto que executa o HWC e gostaria de manter o site fora da árvore de aplicativos, mas não quero mantê-lo no diretório de depuração (ou liberação). FWIW, a solução aceita (e essa também) apenas identifica o diretório em que o executável está sendo executado.

Para encontrar esse diretório, eu tenho usado

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

Com base na resposta de Gucu112 , mas para o aplicativo .NET Core Console / Window, deve ser:

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

Estou usando isso em um projeto xUnit para um aplicativo .NET Core Window.

zwcloud
fonte
4

Outra maneira de fazer isso

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

Se você deseja obter o caminho para a pasta bin

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

Talvez haja uma maneira melhor =)

Tret
fonte
4

Ainda outra solução imperfeita (mas talvez um pouco mais perto da perfeição do que algumas outras):

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

Esta versão retornará a pasta dos projetos atuais, mesmo que o projeto atual não seja o Startup Projectda solução.

A primeira falha disso é que eu pulei toda a verificação de erros. Isso pode ser corrigido com bastante facilidade, mas só deve ser um problema se você estiver armazenando seu projeto no diretório raiz da unidade ou usando uma junção no caminho (e essa junção é descendente da pasta da solução), portanto, esse cenário é improvável. . Não tenho certeza de que o Visual Studio possa lidar com qualquer uma dessas configurações de qualquer maneira.

Outro problema (mais provável) que você pode encontrar é que o nome do projeto deve corresponder ao nome da pasta para o projeto ser encontrado.

Outro problema que você pode ter é que o projeto deve estar dentro da pasta da solução. Isso geralmente não é um problema, mas se você tiver usado a Add Existing Project to Solutionopção de adicionar o projeto à solução, talvez não seja assim que sua solução está organizada.

Por fim, se seu aplicativo modificar o diretório ativo, você deverá armazenar esse valor antes de fazer isso, pois esse valor é determinado em relação ao diretório ativo atual.

Obviamente, tudo isso também significa que você não deve alterar os valores padrão das opções de seus projetos ' Build-> Output pathou Debug-> Working directoryna caixa de diálogo de propriedades do projeto.

krowe
fonte
4

Tente isso, é simples

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

Essa solução funciona bem para mim, nos servidores Develop e também nos servidores TEST e PROD com o ASP.NET MVC5 via C # :

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

Se você precisar do diretório do projeto no arquivo de configuração do projeto, use:

$(ProjectDir)
Jan Sršeň
fonte
3

Depois que eu finalmente terminei de polir minha primeira resposta em relação a nós de cadeias públicas para obter uma resposta, ocorreu-me que você provavelmente poderia ler um valor do registro para obter o resultado desejado. Acontece que essa rota era ainda mais curta:

Primeiro, você deve incluir o espaço para nome Microsoft.Win32 para poder trabalhar com o registro:

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

Aqui está o código principal:

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

Uma observação sobre esta resposta:

Estou usando o Visual Studio 2008 Professional Edition. Se você estiver usando outra versão (2003, 2005, 2010; etc.), talvez seja necessário modificar a parte 'version' da string SubKey (8.0, 7.0; etc.).

Se você usar uma das minhas respostas, e se não for pedir muito, gostaria de saber quais dos meus métodos você usou e por quê. Boa sorte.

  • dm
digitalmythology
fonte
3

Eu tive uma situação semelhante e, depois de Googles infrutíferos, declarei uma string pública, que modifica um valor de string do caminho de depuração / lançamento para obter o caminho do projeto. Uma vantagem de usar esse método é que, como ele usa o diretório do projeto currect, não importa se você estiver trabalhando em um diretório de depuração ou diretório de 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;
}

Você seria capaz de chamá-lo quando quiser, usando apenas uma linha:

string MyProjectDir = DirProject();

Isso deve funcionar na maioria dos casos.

digitalmythology
fonte
3

Use isso para obter o diretório do projeto (funcionou para mim):

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

Eu usei a seguinte solução para fazer o trabalho:

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

Experimentar:

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

Esta é uma solução diferente das outras, também leva em consideração a possível compilação x86 ou x64.

David Desmaisons
fonte
Essa solução está quase lá também para os novos arquivos csproj, onde o TargetFramework está incluído no caminho.
Glenn Watson
1
Para o novo formato de estilo .netcore, eu tinha o novo Regex (@ "\\ bin (\\ x86 | \\ x64)? \ (Debug | Release) (\ [a-zA-Z0-9.] *)? $" (RegexOptions.Compiled)
Glenn Watson
1

A melhor solução

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

Outra solução

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

Testá-lo, AppDomain.CurrentDomain.BaseDirectory funcionou para mim no projeto passado, agora recebo a pasta de depuração .... a resposta BOA selecionada simplesmente NÃO FUNCIONA !.

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

Se você realmente deseja garantir a obtenção do diretório do projeto de origem, não importa em que caminho da saída da bandeja esteja definido:

  1. Adicione uma linha de comando do evento de pré-construção (Visual Studio: Propriedades do projeto -> Construir eventos):

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

  2. Inclua o ProjectDirectory.txtarquivo no arquivo Resources.resx do projeto (se ainda não existir, clique com o botão direito do mouse em projeto -> Adicionar novo item -> arquivo Recursos)

  3. Acesse do código com Resources.ProjectDirectory.
FunctorSalad
fonte
-1

Isso funciona nas configurações do VS2017 com SDK Core MSBuild.

Você precisa do NuGet nos pacotes EnvDTE / EnvDTE80.

Não use COM ou interoperabilidade. qualquer coisa .... lixo !!

 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);
    }
  }
Latência
fonte
-6

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

Fornecerá o diretório do projeto.

brian kitcehner
fonte
77
realmente? Eu acho que você está perdendo um pai
sean