Как получить путь к исполняемому файлу консольного приложения в .NET?
Правильный способ: AppContext.BaseDirectory
В современном .NET (начиная с .NET Core 3.0 и во всех версиях .NET 5/6/7/8/9) самый надёжный и простой способ получить путь к папке с исполняемым файлом — использовать свойство AppContext.BaseDirectory. Оно возвращает именно базовую директорию приложения (где лежит .dll или .exe), с завершающим обратным слешем.
using System;
class Program
{
static void Main()
{
string appPath = AppContext.BaseDirectory;
Console.WriteLine($"Путь к приложению: {appPath}");
// Чтение файла из той же папки
string settingsPath = Path.Combine(appPath, "settings.json");
if (File.Exists(settingsPath))
{
string json = File.ReadAllText(settingsPath);
Console.WriteLine($"Файл найден: {settingsPath}");
}
}
}
Почему это работает надёжно?
- Не зависит от текущей рабочей директории — в отличие от
Environment.CurrentDirectory, который меняется при запуске из другого места. - Корректно работает при shadow copying — возвращает реальную папку, а не временную (в отличие от
Assembly.Locationв некоторых сценариях). - Работает одинаково для single-file публикации, когда приложение упаковано в один .exe файл.
- Не требует дополнительных using — доступен из пространства имён
System.
Другие варианты и их недостатки
Вариант 1: Assembly.GetExecutingAssembly().Location
string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
Этот способ работает, но имеет два недостатка:
- При shadow copying (например, в ASP.NET или некоторых тестовых средах) может вернуть временный путь.
- Требует ссылки на
System.Reflectionи вызоваPath.GetDirectoryNameдля отсечения имени файла.
Вариант 2: Environment.GetCommandLineArgs()[0]
string path = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);
Ненадёжный: при запуске через ассоциацию файлов или из PATH может вернуть только имя файла без полного пути.
Вариант 3: Process.GetCurrentProcess().MainModule.FileName
string path = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
Работает, но медленнее и требует System.Diagnostics. При single-file публикации может вернуть путь к временной папке.
Рекомендация
Используйте AppContext.BaseDirectory — это официально рекомендуемый Microsoft способ для консольных приложений. Он простой, быстрый и надёжный во всех сценариях. Если вам нужно получить именно путь к .exe файлу (а не к папке), дополните код так:
string exePath = Path.Combine(AppContext.BaseDirectory, AppDomain.CurrentDomain.FriendlyName + ".exe");
Но в 99% случаев вам нужна именно папка, чтобы читать или сохранять файлы рядом с приложением. AppContext.BaseDirectory идеально подходит для этой задачи.
Альтернативный подход: использование Directory.GetCurrentDirectory() с проверкой
Если ваше приложение всегда запускается из своей папки (например, через ярлык или из проводника), можно использовать Environment.CurrentDirectory, но с предварительной проверкой:
string appDir = AppDomain.CurrentDomain.BaseDirectory;
Console.WriteLine($"Базовый домен: {appDir}");
Свойство AppDomain.CurrentDomain.BaseDirectory — это устаревший синоним AppContext.BaseDirectory (доступен с .NET Framework 1.0). В .NET Core/5+ он работает идентично, но Microsoft рекомендует переходить на AppContext.BaseDirectory.
Дополнительный совет для кросс-платформенности
Если ваше приложение должно работать и на Windows, и на Linux, используйте Path.Combine для сборки путей и не полагайтесь на жёстко закодированные обратные слеши:
string configPath = Path.Combine(AppContext.BaseDirectory, "config", "appsettings.json");
// На Windows: C:\MyApp\config\appsettings.json
// На Linux: /home/user/MyApp/config/appsettings.json
Также учтите, что при публикации как single-file (один .exe файл) папка приложения — это временная папка, куда распаковываются файлы. В этом случае AppContext.BaseDirectory вернёт путь к этой временной папке, а не к месту, где лежит исходный .exe. Если вам нужен именно исходный путь, используйте Environment.ProcessPath (доступен в .NET 6+):
string originalExePath = Environment.ProcessPath; // Полный путь к исходному .exe
string originalDir = Path.GetDirectoryName(originalExePath);