¿Cómo puedo obtener la ruta de la aplicación en una aplicación de consola .NET?

953

¿Cómo encuentro la ruta de la aplicación en una aplicación de consola?

En Windows Forms , puedo usar Application.StartupPathpara encontrar la ruta actual, pero esto no parece estar disponible en una aplicación de consola.

JSmyth
fuente
55
¿Instalan .NET Framework en la máquina de destino (Cliente, Desarrollo)? si tu respuesta es verdadera; Por lo tanto, puede agregar una referencia a System.Windows.Forms.dll y usar Application.StartupPath! ¡Esta es la mejor manera si desea eliminar futuras excepciones futuras!
Ehsan Mohammadi
AppDomain.BaseDirectory es el directorio de la aplicación. Tenga en cuenta que la aplicación puede comportarse de manera diferente en VS env y Win env. Pero AppDomain debería ser el mismo, no como application.path, pero espero que esto no sea solo para IIS.
Mertuarez

Respuestas:

1179

System.Reflection.Assembly.GetExecutingAssembly(). 1Location

Combina eso con System.IO.Path.GetDirectoryNamesi todo lo que quieres es el directorio.

1 Según el comentario del Sr.Mindor:
System.Reflection.Assembly.GetExecutingAssembly().Location regresa donde se encuentra actualmente el ensamblaje ejecutor, que puede o no ser donde se ubica el ensamblaje cuando no se está ejecutando. En el caso de los ensamblados de instantáneas, obtendrá una ruta en un directorio temporal. System.Reflection.Assembly.GetExecutingAssembly().CodeBasedevolverá la ruta 'permanente' de la asamblea.

Sam Axe
fuente
243
System.Reflection.Assembly.GetExecutingAssembly (). Location devuelve donde se encuentra actualmente el ensamblado en ejecución , que puede o no estar donde se encuentra el ensamblaje cuando no se está ejecutando. En el caso de los ensamblados de instantáneas, obtendrá una ruta en un directorio temporal. System.Reflection.Assembly.GetExecutingAssembly (). CodeBase devolverá la ruta ' permanente ' del ensamblado.
Mr.Mindor
13
@SamGoldberg: Eso depende de cómo se use: stackoverflow.com/q/1068420/391656 . O puede ... nuevo Uri (System.Reflection.Assembly.GetExecutingAssembly (). CodeBase) .LocalPath
Mr.Mindor
28
GetExecutingAssemblydevuelve el ensamblado que contiene el código que se está ejecutando actualmente . Esto puede no ser necesariamente el ensamblado .exe de la consola . Puede ser un ensamblaje que se ha cargado desde una ubicación totalmente diferente. Tendrás que usar GetEntryAssembly! También tenga en cuenta que es CodeBaseposible que no se configure cuando el ensamblaje está en el GAC. La mejor alternativa es AppDomain.CurrentDomain.BaseDirectory.
bitbonk
3
Escriba el código en 4 espacios para que sea cómodo de copiar
fnc12
3
si llama a dll, System.Reflection.Assembly.GetExecutingAssembly (). CodeBase obtendrá "file: /// C: /Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll"
raidsan
407

Puede usar el siguiente código para obtener el directorio de la aplicación actual.

AppDomain.CurrentDomain.BaseDirectory
Richard Ev
fuente
43
No uses esto. BaseDirectory se puede configurar en tiempo de ejecución. No se garantiza que sea correcto (como lo es la respuesta aceptada).
usr
3
+1 Esta es probablemente la respuesta que desea, ya que compensa las instantáneas.
George Mauer
44
@usr ¿Qué te hace pensar que BaseDirectoryse puede configurar en tiempo de ejecución? Solo tiene un captador.
bitbonk
3
@bitbonk se puede configurar en el momento de creación del dominio de aplicación.
usr
3
¿No es que BaseDirectory se puede cambiar en un archivo * .lnk, en el campo "Iniciar en:"?
Alexander
170

Tiene dos opciones para encontrar el directorio de la aplicación, que elija dependerá de su propósito.

// to get the location the assembly is executing from
//(not necessarily where the it normally resides on disk)
// in the case of the using shadow copies, for instance in NUnit tests, 
// this will be in a temp directory.
string path = System.Reflection.Assembly.GetExecutingAssembly().Location;

//To get the location the assembly normally resides on disk or the install directory
string path = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;

//once you have the path you get the directory with:
var directory = System.IO.Path.GetDirectoryName(path);
Mr.Mindor
fuente
3
Solo quería decir, obviamente, hay muchas más de 2 opciones según la cantidad de otras opciones publicadas ...
vapcguy
17
Si lo que sea que intente hacer con dicha ruta no admite el formato URI, usevar localDirectory = new Uri(directory).LocalPath;
Scott Solmer el
Esto está mal. ¿Cuál es el ejecutable no es un ensamblado .NET en absoluto? La respuesta correcta es verificar el entorno e inspeccionar la línea de comando.
marca
@ Ukuma.Scott Esto no funciona si la ruta contiene & o #
MatsW
82

Probablemente un poco tarde, pero vale la pena mencionarlo:

Environment.GetCommandLineArgs()[0];

O más correctamente para obtener solo la ruta del directorio:

System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);

Editar:

Muchas personas han señalado que GetCommandLineArgsno se garantiza que devuelva el nombre del programa. Consulte La primera palabra en la línea de comando es el nombre del programa solo por convención . El artículo establece que "Aunque muy pocos programas de Windows usan este capricho (no conozco ninguno)". Por lo tanto, es posible "falsificar" GetCommandLineArgs, pero estamos hablando de una aplicación de consola. Las aplicaciones de consola suelen ser rápidas y sucias. Entonces esto encaja con mi filosofía KISS.

Steve Mc
fuente
1
@usr la situación a la que te refieres es muy teórica. En el contexto de una aplicación de consola, realmente no tiene sentido usar ningún otro método. ¡Mantenlo simple!
Steve Mc
1
@usr mmm: mirar la columna de cmcm de taskmgr respalda lo que estoy diciendo. Algunos servicios del sistema con solo el nombre exe. No importa. Lo que intento decir es que al desarrollar una aplicación de consola no hay necesidad de complicar las cosas más de lo necesario. Especialmente cuando ya tenemos la información disponible. Ahora, si está ejecutando una aplicación de consola para engañar a GetCommandLineArgs, entonces ya está saltando a través de los aros y probablemente deba preguntarse si una aplicación de consola es el camino correcto.
Steve Mc
55
Su solución "simple" implica dos llamadas a métodos. La solución "complicada" involucra dos llamadas a métodos. No hay diferencia práctica, excepto que la solución "simple" puede darle una respuesta incorrecta en ciertas circunstancias que no están bajo su control cuando está escribiendo el programa. ¿Por qué correr el riesgo? Use las otras dos llamadas de método, y su programa no será más complicado pero será más confiable.
Chris
3
Funcionó para mi escenario, las otras soluciones no lo hicieron, así que gracias por proporcionar otra alternativa :-) Estaba usando ReSharper test runner para ejecutar una prueba de MS Unit y el código que estaba probando necesitaba un .dll específico para estar en el directorio de ejecución. .. y Assembly.GetExecutingDirectory () extrañamente devuelve un resultado diferente.
wallismark
1
@ Chris - en defensa de esta respuesta. Funciona para pruebas unitarias, la solución GetEntryAssembly no lo hace, porque GetEntryAssembly devuelve nulo. Las respuestas que proponen GetExecutingAssembly son falsas, porque solo devuelven el ejecutable si el ensamblaje de ejecución es el ejecutable. Esto no es simple, sino la solución correcta.
marca el
44

Para cualquier persona interesada en las aplicaciones web asp.net. Aquí están mis resultados de 3 métodos diferentes

protected void Application_Start(object sender, EventArgs e)
{
  string p1 = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  string p2 = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
  string p3 = this.Server.MapPath("");
  Console.WriteLine("p1 = " + p1);
  Console.WriteLine("p2 = " + p2);
  Console.WriteLine("p3 = " + p3);
}

resultado

p1 = C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\a897dd66\ec73ff95\assembly\dl3\ff65202d\29daade3_5e84cc01
p2 = C:\inetpub\SBSPortal_staging\
p3 = C:\inetpub\SBSPortal_staging

la aplicación se ejecuta físicamente desde "C: \ inetpub \ SBSPortal_staging", por lo que la primera solución definitivamente no es apropiada para aplicaciones web.

cohetes
fuente
42

La respuesta anterior fue el 90% de lo que necesitaba, pero me devolvió un Uri en lugar de un camino normal.

Como se explica en la publicación de foros de MSDN, ¿Cómo convertir la ruta URI a la ruta de archivo normal? , Usé lo siguiente:

// Get normal filepath of this assembly's permanent directory
var path = new Uri(
    System.IO.Path.GetDirectoryName(
        System.Reflection.Assembly.GetExecutingAssembly().CodeBase)
    ).LocalPath;
fracasó
fuente
1
esto también funciona bien si el exe en cuestión es un servicio de Windows y el directorio actual devuelve C: \ Windows \ system32. El código anterior devuelve la ubicación real del exe
DaImTo
Excepto si intenta hacer algo así File.CreateDirectory(path), se le dará la excepción de que no permite URI caminos ...
vapcguy
1
Desafortunadamente, esto no funciona para las rutas que contienen un identificador de fragmento (el #carácter). El identificador y todo lo que sigue se trunca de la ruta resultante.
bgfvdu3w
¿Por qué no intercambias new Uriy System.IO.Path.GetDirectoryName? Eso te da una cadena de ruta normal en lugar de a Uri.
Timo
Encuentro este el mejor. Este mismo enfoque ha funcionado de manera confiable para mí en cualquier entorno. En producción, depuración local, pruebas unitarias ... ¿Desea abrir un archivo de contenido que incluyó ("contenido - copiar si es más nuevo") en una prueba unitaria? Está allá.
Timo
29

Puede que estés buscando hacer esto:

System.IO.Path.GetDirectoryName(
    System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)
ist_lion
fuente
23

puedes usar este en su lugar.

System.Environment.CurrentDirectory
ButtShock
fuente
Sin embargo
Iain
Esto se puede cambiar de varias maneras (configuración de acceso directo, etc.) ... mejor NO usarlo.
Yousha Aleayoub
23

Si está buscando una forma compatible con .NET Core, use

System.AppContext.BaseDirectory

Esto se introdujo en .NET Framework 4.6 y .NET Core 1.0 (y .NET Standard 1.3). Ver: AppContext.BaseDirectory Property .

De acuerdo con esta página ,

Este es el reemplazo preferido para AppDomain.CurrentDomain.BaseDirectory en .NET Core

Dejan
fuente
1
Consulte también github.com/dotnet/runtime/issues/13051 para ver las aplicaciones de consola dotnet autónomas. La recomendación aquí es usarProcess.GetCurrentProcess().MainModule.FileName
Gavin
19

Para aplicaciones de consola, puede probar esto:

System.IO.Directory.GetCurrentDirectory();

Salida (en mi máquina local):

c: \ users \ xxxxxxx \ documents \ visual studio 2012 \ Projects \ ImageHandler \ GetDir \ bin \ Debug

O puede intentarlo (hay una barra invertida adicional al final):

AppDomain.CurrentDomain.BaseDirectory

Salida:

c: \ users \ xxxxxxx \ documents \ visual studio 2012 \ Projects \ ImageHandler \ GetDir \ bin \ Debug \

F.Alves
fuente
"Se BaseDirectorypuede configurar en tiempo de ejecución. NO se garantiza que sea correcto"
Yousha Aleayoub
14

He usado este código y obtengo la solución.

AppDomain.CurrentDomain.BaseDirectory
Solución de software Trimantra
fuente
9

Simplemente puede agregar a sus referencias de proyecto System.Windows.Formsy luego usar las de System.Windows.Forms.Application.StartupPath siempre.

Por lo tanto, no es necesario utilizar métodos más complicados o usar la reflexión.

fruggiero
fuente
Usé ese, y funciona bien. Pero una vez usé el método que lo tenía en mi proyecto de prueba de unidad. Y, por supuesto, falló porque estaba buscando mi archivo en C: \ PROGRAM FILES (X86) \ MICROSOFT VISUAL STUDIO 14.0 \ COMMON7 \ IDE \ COMMONEXTENSIONS \ MICROSOFT \ TESTWINDOW
ainasiart el
@ainasiart, ¿cómo puedo hacer que esto funcione mientras se realizan las pruebas unitarias?
Nicholas Siegmundt
8

La siguiente línea le dará una ruta de aplicación:

var applicationPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)

La solución anterior funciona correctamente en las siguientes situaciones:

  • aplicación simple
  • en otro dominio donde Assembly.GetEntryAssembly () devolvería nulo
  • La DLL se carga desde los recursos integrados como una matriz de bytes y se carga en AppDomain como Assembly.Load (byteArrayOfEmbeddedDll)
  • con los mkbundlepaquetes de Mono (ningún otro método funciona)
user2126375
fuente
Bajo depurador en Linux, esto devuelve: / usr / share / dotnet
Vladimir
7

Lo uso si se supone que se llama al exe haciendo doble clic en él

var thisPath = System.IO.Directory.GetCurrentDirectory();
desarrollador747
fuente
55
Esto no es correcto porque puede obtener directorios aleatorios en el resultado.
amuliar el
Este comando devuelve Environment.CurrentDirectory, que se puede cambiar en tiempo de ejecución a cualquier ruta, por lo que no es una solución confiable.
Yury Kozlov el
7

He usado

System.AppDomain.CurrentDomain.BaseDirectory

cuando quiero encontrar una ruta relativa a una carpeta de aplicaciones. Esto funciona tanto para ASP.Net como para aplicaciones winform. Tampoco requiere ninguna referencia a los ensamblados System.Web.

usuario2346593
fuente
6

Quiero decir, ¿por qué no un método ap / invoke?

    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    public class AppInfo
    {
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false)]
            private static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);
            private static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);
            public static string StartupPath
            {
                get
                {
                    StringBuilder stringBuilder = new StringBuilder(260);
                    GetModuleFileName(NullHandleRef, stringBuilder, stringBuilder.Capacity);
                    return Path.GetDirectoryName(stringBuilder.ToString());
                }
            }
    }

Lo usarías al igual que Application.StartupPath:

    Console.WriteLine("The path to this executable is: " + AppInfo.StartupPath + "\\" + System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe");
usuario3596865
fuente
2
¿Por qué p / invocar cuando hay tanto .NET para esto?
ProfK
77
@ user3596865 porque requiere una fuerte dependencia de Windows y no es compatible con DNX o Mono. Y tal vez haya un cambio radical en futuras versiones de Windows. Así que de nuevo: ¿por qué deberíamos usar pinvoke aquí?
Ben
5

Assembly.GetEntryAssembly().Location o Assembly.GetExecutingAssembly().Location

Use en combinación con System.IO.Path.GetDirectoryName()para obtener solo el directorio.

Las rutas desde GetEntryAssembly()y GetExecutingAssembly()pueden ser diferentes, aunque en la mayoría de los casos el directorio será el mismo.

Tenga GetEntryAssembly()en cuenta que esto puede volver nullsi el módulo de entrada no está administrado (es decir, C ++ o VB6 ejecutable). En esos casos, es posible usar GetModuleFileNamedesde la API de Win32:

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);
Germán
fuente
5

en VB.net

My.Application.Info.DirectoryPath

funciona para mí (Tipo de aplicación: Biblioteca de clases). No estoy seguro acerca de C # ... Devuelve la ruta sin nombre de archivo como cadena

dba
fuente
4
AppDomain.CurrentDomain.BaseDirectory

Resolverá el problema para referir los archivos de referencia de terceros con paquetes de instalación.

Nirav Mehta
fuente
11
Esta respuesta ya se sugirió hace 5 años, incluso más de una vez.
PL
2

Ninguno de estos métodos funciona en casos especiales como el uso de un enlace simbólico al exe, devolverán la ubicación del enlace, no el exe real.

Entonces, puede usar QueryFullProcessImageName para evitar eso:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;

internal static class NativeMethods
{
    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern bool QueryFullProcessImageName([In]IntPtr hProcess, [In]int dwFlags, [Out]StringBuilder lpExeName, ref int lpdwSize);

    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern IntPtr OpenProcess(
        UInt32 dwDesiredAccess,
        [MarshalAs(UnmanagedType.Bool)]
        Boolean bInheritHandle,
        Int32 dwProcessId
    );
}

public static class utils
{

    private const UInt32 PROCESS_QUERY_INFORMATION = 0x400;
    private const UInt32 PROCESS_VM_READ = 0x010;

    public static string getfolder()
    {
        Int32 pid = Process.GetCurrentProcess().Id;
        int capacity = 2000;
        StringBuilder sb = new StringBuilder(capacity);
        IntPtr proc;

        if ((proc = NativeMethods.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid)) == IntPtr.Zero)
            return "";

        NativeMethods.QueryFullProcessImageName(proc, 0, sb, ref capacity);

        string fullPath = sb.ToString(0, capacity);

        return Path.GetDirectoryName(fullPath) + @"\";
    }
}
colin lamarre
fuente
2

Pruebe esta simple línea de código:

 string exePath = Path.GetDirectoryName( Application.ExecutablePath);
daniele3004
fuente
1

Otra solución es usar rutas relativas que apuntan a la ruta actual:

Path.GetFullPath(".")
blenderfreaky
fuente
Esto obtiene el directorio actual, no la ubicación del EXE inicial.
diez
0

No vi a nadie convertir el LocalPath proporcionado por la reflexión de .Net Core en una ruta utilizable de System.IO, así que aquí está mi versión.

public static string GetApplicationRoot()
{
   var exePath = new Uri(System.Reflection.
   Assembly.GetExecutingAssembly().CodeBase).LocalPath;

   return new FileInfo(exePath).DirectoryName;

}

Esto devolverá la ruta formateada "C: \ xxx \ xxx" completa a donde está su código.

Mark Gamache
fuente
-1

Aquí hay una solución confiable que funciona con aplicaciones de 32 bits y 64 bits .

Agregue estas referencias:

utilizando System.Diagnostics;

usando System.Management;

Agregue este método a su proyecto:

public static string GetProcessPath(int processId)
{
    string MethodResult = "";
    try
    {
        string Query = "SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = " + processId;

        using (ManagementObjectSearcher mos = new ManagementObjectSearcher(Query))
        {
            using (ManagementObjectCollection moc = mos.Get())
            {
                string ExecutablePath = (from mo in moc.Cast<ManagementObject>() select mo["ExecutablePath"]).First().ToString();

                MethodResult = ExecutablePath;

            }

        }

    }
    catch //(Exception ex)
    {
        //ex.HandleException();
    }
    return MethodResult;
}

Ahora úsalo así:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

Tenga en cuenta que si conoce la identificación del proceso, este método devolverá el ExecutePath correspondiente.

Extra, para los interesados:

Process.GetProcesses() 

... le dará una serie de todos los procesos que se ejecutan actualmente, y ...

Process.GetCurrentProcess()

... le dará el proceso actual, junto con su información, por ejemplo, Id, etc. y también un control limitado, por ejemplo, Kill, etc. *

WonderWorker
fuente
-5

Puede crear un nombre de carpeta como Recursos dentro del proyecto usando el Explorador de soluciones, luego puede pegar un archivo dentro de los Recursos.

private void Form1_Load(object sender, EventArgs e) {
    string appName = Environment.CurrentDirectory;
    int l = appName.Length;
    int h = appName.LastIndexOf("bin");
    string ll = appName.Remove(h);                
    string g = ll + "Resources\\sample.txt";
    System.Diagnostics.Process.Start(g);
}
Devarajan.T
fuente
66
Usar Environment.CurrentDirectory está muy mal, ¡no lo uses! Este camino puede cambiar en tiempo de ejecución. Incluso en el inicio no es determinista.
usr