Bagaimana saya bisa mendapatkan jalur aplikasi di aplikasi .NET console?

953

Bagaimana cara menemukan jalur aplikasi di aplikasi konsol?

Di Windows Forms , saya dapat menggunakan Application.StartupPathuntuk menemukan jalur saat ini, tetapi ini sepertinya tidak tersedia di aplikasi konsol.

JSmyth
sumber
5
Apakah Anda menginstal .NET Framework pada mesin target (Klien, Pengembangan)? jika jawaban Anda benar; Jadi, Anda dapat menambahkan referensi ke System.Windows.Forms.dll dan gunakan Application.StartupPath! Ini adalah cara terbaik jika Anda ingin meninggalkan pengecualian lebih lanjut di masa depan!
Ehsan Mohammadi
AppDomain.BaseDirectory adalah direktori aplikasi. Sadarilah bahwa aplikasi dapat berperilaku berbeda dalam VS env dan Win env. Tetapi AppDomain harus sama bukan dengan application.path tetapi saya berharap ini bukan hanya untuk IIS.
Mertuarez

Jawaban:

1179

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

Kombinasikan dengan System.IO.Path.GetDirectoryNamejika yang Anda inginkan adalah direktori.

1 Sesuai komentar Mr.Mindor:
System.Reflection.Assembly.GetExecutingAssembly().Location mengembalikan tempat majelis pelaksana saat ini berada, yang mungkin atau mungkin tidak di mana majelis berada saat tidak menjalankan. Dalam kasus rakitan penyalinan bayangan, Anda akan mendapatkan lintasan di direktori temp. System.Reflection.Assembly.GetExecutingAssembly().CodeBaseakan mengembalikan jalur 'permanen' majelis.

Sam Axe
sumber
243
System.Reflection.Assembly.GetExecutingAssembly (). Lokasi mengembalikan tempat majelis pelaksana saat ini berada, yang mungkin atau mungkin tidak di mana majelis berada saat tidak menjalankan. Dalam kasus rakitan penyalinan bayangan, Anda akan mendapatkan lintasan di direktori temp. System.Reflection.Assembly.GetExecutingAssembly (). CodeBase akan mengembalikan jalur ' permenant ' dari rakitan.
Mr.Mindor
13
@ SamGoldberg: Itu tergantung pada bagaimana penggunaannya: stackoverflow.com/q/1068420/391656 . Atau Anda dapat ... Uri baru (System.Reflection.Assembly.Get ExecutingAssembly (). CodeBase) .LocalPath
Mr.Mindor
28
GetExecutingAssemblymengembalikan perakitan yang berisi kode yang saat ini dieksekusi . Ini mungkin belum tentu merupakan konsol .exe . Mungkin perakitan yang telah dimuat dari lokasi yang sama sekali berbeda. Anda harus menggunakan GetEntryAssembly! Perhatikan juga bahwa CodeBasemungkin tidak diatur ketika perakitan di GAC. Alternatif yang lebih baik adalah AppDomain.CurrentDomain.BaseDirectory.
bitbonk
3
Silakan tulis kode dalam 4 spasi sehingga nyaman untuk menyalin
fnc12
3
jika Anda memanggil dll, System.Reflection.Assembly.GetExecutingAssembly (). CodeBase akan mendapatkan "file: /// C: /Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll"
raidsan
407

Anda dapat menggunakan kode berikut untuk mendapatkan direktori aplikasi saat ini.

AppDomain.CurrentDomain.BaseDirectory
Richard Ev
sumber
43
Jangan gunakan ini. BaseDirectory dapat diatur pada saat runtime. Itu tidak dijamin benar (seperti jawaban yang diterima).
usr
3
+1 Ini kemungkinan jawaban yang Anda inginkan karena mengkompensasi penyalinan bayangan.
George Mauer
4
@ usr Apa yang membuat Anda berpikir bahwa BaseDirectorydapat diatur saat runtime? Ini hanya memiliki rajin dan giat.
bitbonk
3
@bitbonk dapat disetel pada waktu pembuatan appdomain.
usr
3
Bukankah BaseDirectory dapat diubah dalam file * .lnk, di bidang "Mulai di:"?
Alexander
170

Anda memiliki dua opsi untuk menemukan direktori aplikasi, yang Anda pilih tergantung pada tujuan Anda.

// 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
sumber
3
Hanya ingin mengatakan, jelas ada banyak lebih dari 2 opsi dengan berapa banyak pilihan lain yang diposting ...
vapcguy
17
Jika apa pun yang Anda coba lakukan dengan jalur kata tidak mendukung format URI, gunakanvar localDirectory = new Uri(directory).LocalPath;
Scott Solmer
Ini salah. Apakah yang dapat dieksekusi itu bukan .NET assembly? Jawaban yang tepat adalah memeriksa lingkungan dan memeriksa baris perintah.
tandai
@ Ukuma.Scott Ini tidak berfungsi jika path berisi & atau #
MatsW
82

Mungkin agak terlambat tapi ini layak disebutkan:

Environment.GetCommandLineArgs()[0];

Atau lebih tepatnya untuk mendapatkan hanya jalur direktori:

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

Edit:

Beberapa orang telah menunjukkan bahwa GetCommandLineArgstidak dijamin untuk mengembalikan nama program. Lihat Kata pertama pada baris perintah adalah nama program hanya dengan konvensi . Artikel itu menyatakan bahwa "Meskipun sangat sedikit program Windows menggunakan kekhasan ini (saya sendiri tidak mengetahui adanya)". Jadi dimungkinkan untuk 'spoof' GetCommandLineArgs, tetapi kita berbicara tentang aplikasi konsol. Aplikasi konsol biasanya cepat dan kotor. Jadi ini cocok dengan filosofi KISS saya.

Steve Mc
sumber
1
@ usr situasi yang Anda singgung sangat teoretis. Dalam konteks aplikasi konsol, tidak masuk akal untuk menggunakan metode lain. Tetap sederhana!
Steve Mc
1
@ usr mmm - melihat kolom cmdline taskmgr semacam mendukung apa yang saya katakan. Beberapa layanan sistem dengan hanya nama exe. Sudahlah. Yang ingin saya katakan adalah bahwa ketika mengembangkan aplikasi konsol tidak perlu membuat hal-hal lebih rumit daripada yang seharusnya. Terutama ketika kita sudah memiliki informasi yang tersedia. Sekarang, jika Anda menjalankan aplikasi konsol sedemikian rupa untuk mengelabui GetCommandLineArgs maka Anda sudah melompat-lompat dan Anda mungkin perlu bertanya pada diri sendiri apakah aplikasi konsol adalah cara yang tepat untuk digunakan.
Steve Mc
5
Solusi "sederhana" Anda melibatkan dua panggilan metode. Solusi "rumit" melibatkan dua pemanggilan metode. Tidak ada perbedaan praktis - kecuali bahwa solusi "sederhana" dapat memberi Anda jawaban yang salah dalam keadaan tertentu yang tidak di bawah kendali Anda ketika Anda sedang menulis program. Mengapa mengambil risiko? Gunakan dua panggilan metode lainnya, dan program Anda tidak akan lebih rumit tetapi akan lebih dapat diandalkan.
Chris
3
Bekerja untuk skenario saya, solusi lain tidak, jadi terima kasih telah memberikan alternatif lain :-) Saya menggunakan test runner ReSharper untuk menjalankan tes MS Unit dan kode yang saya uji membutuhkan. ..dan Assembly.GetExecutingDirectory () anehnya mengembalikan hasil yang berbeda.
wallismark
1
@ Chris - untuk membela jawaban ini. Ini berfungsi untuk pengujian unit, solusi GetEntryAssembly tidak, karena GetEntryAssembly mengembalikan nol. Jawaban yang mengusulkan GetExecutingAssembly adalah palsu, karena mereka hanya mengembalikan yang dapat dieksekusi jika majelis pelaksana adalah yang dapat dieksekusi. Ini bukan solusi yang sederhana, tetapi yang benar.
tandai
44

Bagi siapa pun yang tertarik dengan aplikasi web asp.net. Berikut adalah hasil saya dari 3 metode berbeda

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

hasil

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

aplikasi ini berjalan secara fisik dari "C: \ inetpub \ SBSPortal_staging", jadi solusi pertama jelas tidak sesuai untuk aplikasi web.

rocketsarefast
sumber
42

Jawaban di atas adalah 90% dari yang saya butuhkan, tetapi mengembalikan Uri alih-alih jalur reguler untuk saya.

Seperti yang dijelaskan dalam posting forum MSDN, Bagaimana cara mengubah jalur URI ke file normal? , Saya menggunakan yang berikut ini:

// Get normal filepath of this assembly's permanent directory
var path = new Uri(
    System.IO.Path.GetDirectoryName(
        System.Reflection.Assembly.GetExecutingAssembly().CodeBase)
    ).LocalPath;
gagal
sumber
1
ini berfungsi dengan baik juga jika exe yang dimaksud adalah layanan windows dan direktori saat ini mengembalikan C: \ Windows \ system32. Kode di atas mengembalikan lokasi aktual exe
DaImTo
Kecuali jika Anda kemudian mencoba melakukan sesuatu seperti File.CreateDirectory(path), itu akan memberi Anda pengecualian bahwa itu tidak memungkinkan jalur URI ...
vapcguy
1
Sayangnya ini tidak berfungsi untuk jalur yang berisi pengidentifikasi fragmen ( #karakter). Identifier dan semua yang mengikutinya terpotong dari jalur yang dihasilkan.
bgfvdu3w
Mengapa Anda tidak bertukar new Uridan System.IO.Path.GetDirectoryName? Itu memberi Anda string jalur normal, bukan a Uri.
Timo
Saya menemukan ini yang terbaik. Pendekatan yang sama ini berhasil bagi saya di lingkungan apa pun. Dalam produksi, debugging secara lokal, pengujian unit ... Ingin membuka file konten yang Anda sertakan ("konten - salin jika lebih baru") dalam pengujian unit? Itu disana.
Timo
29

Anda mungkin ingin melakukan ini:

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

Anda dapat menggunakan yang ini sebagai gantinya.

System.Environment.CurrentDirectory
ButtShock
sumber
Ini akan mendapatkan folder yang dapat dieksekusi
Iain
Ini dapat diubah dalam beberapa cara (pengaturan pintasan dll) ... lebih baik untuk TIDAK menggunakannya.
Yousha Aleayoub
23

Jika Anda mencari cara .NET Core yang kompatibel, gunakan

System.AppContext.BaseDirectory

Ini diperkenalkan di .NET Framework 4.6 dan .NET Core 1.0 (dan .NET Standard 1.3). Lihat: AppContext.BaseDirectory Property .

Menurut halaman ini ,

Ini adalah pengganti yang lebih disukai untuk AppDomain.CurrentDomain.BaseDirectory di .NET Core

Dejan
sumber
1
lihat juga github.com/dotnet/runtime/issues/13051 untuk aplikasi konsol dotnet mandiri. Rekomendasi di sini adalah untuk menggunakanProcess.GetCurrentProcess().MainModule.FileName
Gavin
19

Untuk Aplikasi Konsol, Anda dapat mencoba ini:

System.IO.Directory.GetCurrentDirectory();

Output (pada mesin lokal saya):

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

Atau Anda dapat mencoba (ada backslash tambahan pada akhirnya):

AppDomain.CurrentDomain.BaseDirectory

Keluaran:

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

F. Alves
sumber
" BaseDirectoryDapat diatur saat runtime. TIDAK dijamin benar"
Yousha Aleayoub
14

Saya telah menggunakan kode ini dan mendapatkan solusinya.

AppDomain.CurrentDomain.BaseDirectory
Solusi Perangkat Lunak Trimantra
sumber
9

Anda cukup menambahkan referensi proyek Anda System.Windows.Formsdan kemudian menggunakan System.Windows.Forms.Application.StartupPath seperti biasa.

Jadi, tidak perlu metode yang lebih rumit atau menggunakan refleksi.

fruggiero
sumber
Saya menggunakan yang itu, dan itu bekerja dengan baik. Tetapi suatu kali saya menggunakan metode yang ada di proyek unit test saya. Dan tentu saja, itu gagal karena sedang mencari file saya di C: \ PROGRAM FILES (X86) \ MICROSOFT VISUAL STUDIO 14.0 \ COMMON7 \ IDE \ COMMONEXTENSIONS \ MICROSOFT \ TESTWINDOW
ainasiart
@ainasiart jadi bagaimana caranya agar ini berfungsi saat pengujian unit ??
Nicholas Siegmundt
8

Baris berikut akan memberi Anda jalur aplikasi:

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

Solusi di atas berfungsi dengan baik dalam situasi berikut:

  • aplikasi sederhana
  • di domain lain tempat Assembly.GetEntryAssembly () akan mengembalikan nol
  • DLL diambil dari sumber daya Tertanam sebagai array byte dan dimuat ke AppDomain sebagai Assembly.Load (byteArrayOfEmbeddedDll)
  • dengan mkbundlebundel Mono (tidak ada metode lain yang berfungsi)
pengguna2126375
sumber
Di bawah debugger di linux ini mengembalikan: / usr / share / dotnet
Vladimir
7

Saya menggunakan ini jika exe seharusnya dipanggil dengan mengklik dua kali

var thisPath = System.IO.Directory.GetCurrentDirectory();
developer747
sumber
5
Ini tidak benar karena Anda bisa mendapatkan direktori acak di hasilnya.
amuliar
Perintah ini mengembalikan Environment.CurrentDirectory, yang dapat diubah saat runtime ke jalur apa pun, jadi ini bukan solusi yang andal.
Yury Kozlov
7

Saya sudah menggunakan

System.AppDomain.CurrentDomain.BaseDirectory

ketika saya ingin mencari jalur relatif ke folder aplikasi. Ini berfungsi baik untuk aplikasi ASP.Net maupun winform. Itu juga tidak memerlukan referensi ke System.Web rakitan.

pengguna2346593
sumber
6

Maksud saya, mengapa tidak ap / memanggil metode?

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

Anda akan menggunakannya seperti Application.StartupPath:

    Console.WriteLine("The path to this executable is: " + AppInfo.StartupPath + "\\" + System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe");
pengguna3596865
sumber
2
Mengapa p / memohon ketika ada begitu banyak. NET untuk ini?
ProfK
7
@ user3596865 karena ia memerlukan dependensi yang sulit untuk Windows dan tidak kompatibel dengan DNX atau Mono. Dan mungkin ada perubahan pada Versi Windows yang akan datang. Jadi sekali lagi: mengapa kita harus menggunakan pinvoke di sini?
Ben
5

Assembly.GetEntryAssembly().Location atau Assembly.GetExecutingAssembly().Location

Gunakan bersama dengan System.IO.Path.GetDirectoryName()untuk mendapatkan hanya direktori.

Path dari GetEntryAssembly()dan GetExecutingAssembly()dapat berbeda, meskipun untuk sebagian besar kasus direktori akan sama.

Dengan GetEntryAssembly()Anda harus menyadari bahwa ini dapat kembali nulljika modul entri tidak dikelola (yaitu C ++ atau VB6 dapat dieksekusi). Dalam kasus tersebut, dimungkinkan untuk menggunakan GetModuleFileNamedari Win32 API:

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

di VB.net

My.Application.Info.DirectoryPath

berfungsi untuk saya (Tipe Aplikasi: Perpustakaan Kelas). Tidak yakin tentang C # ... Mengembalikan jalur tanpa Nama file sebagai string

dba
sumber
4
AppDomain.CurrentDomain.BaseDirectory

Akan menyelesaikan masalah untuk merujuk file referensi pihak ke-3 dengan paket instalasi.

Nirav Mehta
sumber
11
Jawaban ini sudah disarankan 5 tahun yang lalu, bahkan lebih dari sekali.
PL
2

Tidak satu pun dari metode ini bekerja dalam kasus khusus seperti menggunakan tautan simbolis ke exe, mereka akan mengembalikan lokasi tautan bukan exe yang sebenarnya.

Jadi dapat menggunakan QueryFullProcessImageName untuk menyiasati itu:

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
sumber
2

Coba baris kode sederhana ini:

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

Solusi lain adalah menggunakan jalur relatif yang menunjuk ke jalur saat ini:

Path.GetFullPath(".")
blenderfreaky
sumber
Ini mendapatkan direktori saat ini, bukan lokasi EXE awal.
tenfour
0

Saya tidak melihat siapa pun mengonversi LocalPath yang disediakan oleh .Net Core refleksi ke jalur System.IO yang dapat digunakan jadi inilah versi saya.

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

   return new FileInfo(exePath).DirectoryName;

}

Ini akan mengembalikan path lengkap yang diformat "C: \ xxx \ xxx" ke tempat kode Anda.

tandai gamache
sumber
-1

Berikut ini adalah solusi andal yang bekerja dengan 32bit dan 64bit aplikasi .

Tambahkan referensi ini:

menggunakan System.Diagnostics;

menggunakan System.Management;

Tambahkan metode ini ke proyek Anda:

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

Sekarang gunakan seperti ini:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

Perhatikan bahwa jika Anda mengetahui id proses, maka metode ini akan mengembalikan ExecutePath yang sesuai.

Ekstra, bagi yang berminat:

Process.GetProcesses() 

... akan memberi Anda array dari semua proses yang sedang berjalan, dan ...

Process.GetCurrentProcess()

... akan memberi Anda proses saat ini, bersama dengan informasi mereka misalnya Id, dll. dan juga kendali terbatas mis. Kill, dll. *

WonderWorker
sumber
-5

Anda dapat membuat nama folder sebagai Sumber Daya dalam proyek menggunakan Solution Explorer, lalu Anda dapat menempelkan file di dalam Sumber Daya.

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
sumber
6
Menggunakan Environment.CurrentDirectory sangat salah, jangan gunakan ini! jalur ini dapat berubah saat runtime. Bahkan pada saat startup itu tidak menentukan.
usr