Skip to content

MS_GettingApplicationPaths

nishi_74322014 edited this page Aug 21, 2026 · 1 revision

アプリケーションの様々なパスを取得する方法

概要

調査したところ、

System.AppDomain.CurrentDomain.BaseDirectory

が推奨方法の既定値であるもよう。

補足(この結論は現在も妥当): 原文の結論は正しく、
AppDomain.CurrentDomain.BaseDirectory が最も安全な既定である。

【なぜこれが安全か】
  ・カレント ディレクトリの影響を受けない
  ・単一ファイル発行でも「展開先」ではなく期待する場所を返す(後述)
  ・[アプリケーション ドメイン](MS_ApplicationDomain) が
    .NET Core で廃止されても、このプロパティは残っている

なお、.NET 6 以降では AppContext.BaseDirectory が推奨される
(実体は同じ値を返すが、AppDomain に依存しない名前空間にある)。

var dir = AppContext.BaseDirectory;   // 現在はこちらが素直

方法

System

System 名前空間のライブラリを使用するのが一般的。

System.AppDomain

アプリケーションと同じディレクトリにあるファイルを検索する場合に使用する。

string path = System.AppDomain.CurrentDomain.BaseDirectory;

System.Environment

環境変数の current directory を取得する場合に使用する。

  • アプリケーションの実行中に変化する可能性のある値。
  • OpenFileDialog でファイルを選択されたディレクトリに変更される可能性がある。
string path = System.Environment.CurrentDirectory;

補足(OpenFileDialog の件は現在も要注意): 原文が挙げている
この落とし穴は、既定の挙動として現在も存在する

var dlg = new OpenFileDialog();
dlg.RestoreDirectory = true;   // ← これを true にすると変わらない
dlg.ShowDialog();

RestoreDirectory の既定は false なので、
ファイルを選ぶたびにカレント ディレクトリが移動する。
カレント ディレクトリに依存した相対パスを使っていると、
ある操作の後だけ動かなくなる
という再現しにくい不具合になる。

結論: カレント ディレクトリを当てにしない
相対パスは AppContext.BaseDirectory を基点に組み立てる。

var configPath = Path.Combine(AppContext.BaseDirectory, "config", "app.json");

System.IO

System.Environmentと同じ、
環境変数の current directory を取得する場合に使用する。

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

System.Reflection.Assembly

Assembly クラスの Location プロパティで Assembly のパスを取得できる。

GetEntryAssembly

GetEntryAssembly メソッドでは、EXE などのエントリポイントとなるアセンブリを取得する。

string path = System.Reflection.Assembly.GetEntryAssembly().Location;

移行メモ(誤記): 原文の
string path = System.Reflection.Assembly myAssembly = System.Reflection.Assembly.GetEntryAssembly().Location;
変数宣言が二重になっており、コンパイルできないため、
前後の例に合わせて修正した。
また、本文の「EntryAssembly メソッド」も
GetEntryAssembly メソッドの脱字と判断した。

GetExecutingAssembly

GetExecutingAssembly メソッドでは、
実行中のコードを含む EXE や DLL のアセンブリを取得する。

string path = System.Reflection.Assembly.GetExecutingAssembly().Location;

GetCallingAssembly

GetCallingAssembly メソッドでは、
現在実行中のメソッドを呼び出したコードを含む EXE や DLL のアセンブリを取得する。

string path = System.Reflection.Assembly.GetCallingAssembly().Location;

補足(3 つの使い分け): アセンブリ が複数ある
(EXE + 複数の DLL)場合、返る値が異なる。

MyApp.exe が MyLib.dll の Foo() を呼び、
その中でパスを取得した場合

  GetEntryAssembly()     → MyApp.exe        (入口)
  GetExecutingAssembly() → MyLib.dll        (今いる場所)
  GetCallingAssembly()   → MyApp.exe        (呼び出し元)
用途 使うもの
アプリの設定ファイルを探す AppContext.BaseDirectory(推奨)
ライブラリ自身に付属するファイルを探す GetExecutingAssembly().Location
「誰に呼ばれたか」でふるまいを変える GetCallingAssembly()避けるべき

GetCallingAssembly は使わない方がよい
インライン化や async の書き換えによって期待通りに動かないことがある
async/await のステート マシン化の影響)。

補足(Assembly.Location は単一ファイル発行で空になる/最新化): これは
.NET 5 以降で最も踏みやすい破壊的変更である。

発行形態 Assembly.Location
通常の発行 パスが返る
単一ファイル発行PublishSingleFile 空文字列
Native AOT 空文字列
単一ファイル発行では、アセンブリはメモリ上に展開されるため
「ファイルとしての場所」が存在しない
  → Location は "" を返す(例外ではない点が厄介)
  → Path.GetDirectoryName("") が例外になる、
    あるいは意図しないパスになる

対処は AppContext.BaseDirectory を使うことである
(こちらは単一ファイルでも実行ファイルの場所を返す)。

// ✗ 単一ファイル発行で壊れる
var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

// ○ 常に動く
var dir = AppContext.BaseDirectory;

// 実行ファイル自身のパスが欲しい場合(.NET 6+)
var exe = Environment.ProcessPath;

Environment.ProcessPath(.NET 6 で追加)は、
後述の Application.ExecutablePath
クロスプラットフォーム版にあたる。

なお、単一ファイル発行時に Location を使っているコードは
**ビルド時に警告(IL3000)**が出るため、
警告を有効にしておくと検出できる。

<PublishSingleFile>true</PublishSingleFile>
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>

System.Windows.Forms.Application

Windows.Forms 用

ExecutablePath

string path = Application.ExecutablePath;

StartupPath

string path = Application.StartupPath;

補足(Windows Forms 以外では使えない): この 2 つは
System.Windows.Forms に属するため、
コンソール / Web / ライブラリからは使えない
(参照を追加すれば呼べるが、設計として不適切)。

返す値
Application.ExecutablePath 実行ファイルの「フル パス」(ファイル名を含む)
Application.StartupPath 実行ファイルの「ディレクトリ」

クロスプラットフォームな代替は次の通り。

Environment.ProcessPath          // ExecutablePath 相当(.NET 6+)
AppContext.BaseDirectory         // StartupPath 相当

補足(用途別のまとめ): 実務での選択指針を整理しておく。

欲しいもの 推奨
アプリと同梱したファイル(設定、テンプレート) AppContext.BaseDirectory
実行ファイルそのもののパス Environment.ProcessPath(.NET 6+)
ユーザーごとの設定の保存先 Environment.GetFolderPath(SpecialFolder.ApplicationData)
一時ファイル Path.GetTempPath()
ログの出力先 設定で指定させる(.NET Core config
Web のパス Webサイトのパスを取得する方法

重要: アプリの配置先に書き込まない
Program Files 配下は書き込み権限が無く、
コンテナでは読み取り専用のことが多い。
書き込むものは ApplicationData か、
設定で指定された場所に置く

var appData = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
    "MyCompany", "MyApp");
Directory.CreateDirectory(appData);

なお、ASP.NET Core では IHostEnvironment
注入して使うのが定石である(ASP.NET Core における DI)。

public MyService(IHostEnvironment env)
{
    var root = env.ContentRootPath;   // アプリのルート
}

参考

.NET Tips (VB.NET,C#...)

tekkの日記 C#,VB.NET

Microsoft Learn


Tags: 移行, .NET開発

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally