AppDomain.CurrentDomain.BaseDirectory是最稳的选择,它返回程序集加载的基目录,不受启动方式或工作目录变更影响,适用于多数获取应用根路径的场景。

AppDomain.CurrentDomain.BaseDirectory 是最稳的选择
多数情况下,你要的“AppPath根目录”就是程序集加载的基目录,不是.exe所在目录,也不是工作目录。用 AppDomain.CurrentDomain.BaseDirectory 最可靠,它不受启动方式(快捷方式、命令行、IDE调试)或当前工作目录变更的影响。
常见错误是误用 Environment.CurrentDirectory 或 Directory.GetCurrentDirectory() —— 这俩返回的是进程当前工作目录,可能被代码、Shell或第三方库中途修改,完全不可控。
- Web项目(如ASP.NET Core)中该值指向
bin/Debug或发布后的wwwroot上层,不是网站根路径,别混用 - 如果程序是通过
Assembly.LoadFrom()动态加载的,BaseDirectory仍指向主程序集的基目录,不是被加载DLL的路径 - 在 .NET 5+ 的单文件发布(
publish-self-contained true)模式下,它指向解压临时目录(如%TEMP%.netMyApp...),不是原始发布包路径
Assembly.GetExecutingAssembly().Location 适合获取当前DLL位置
当你明确需要“当前正在执行的程序集(.dll 或 .exe)的完整文件路径”,就用 Assembly.GetExecutingAssembly().Location。它返回磁盘上该程序集的实际物理路径,对诊断加载问题、读取同级配置文件很实用。
注意:这个路径可能是符号链接展开后的真路径(尤其在Linux/macOS),且在单文件发布时指向运行时解压后的临时文件,不是原始打包路径。
- 不要用
Assembly.GetExecutingAssembly().GetName().CodeBase—— 它返回的是URI格式(如file:///...),还可能为空或抛NotSupportedException - 如果调用发生在 NuGet 包的类库中,
GetExecutingAssembly()返回的是那个类库的DLL路径,不是主程序目录 - 想取主程序(.exe)路径?用
Assembly.GetEntryAssembly()?.Location,但要注意:.NET Core/.NET 5+ 的某些宿主(如 dotnet CLI、IIS in-process)可能让EntryAssembly为 null
Application.StartupPath 在 WinForms 中有特殊语义
仅限 Windows Forms 应用,Application.StartupPath 返回的是主可执行文件(.exe)所在的目录,和 AppDomain.BaseDirectory 在多数场景结果一致,但语义更明确——它是 WinForms 框架自己维护的启动上下文路径。
但它不适用于 Console、WPF、ASP.NET 或跨平台项目;而且一旦你把 WinForms 程序以“作为库引用”的方式嵌入其他进程(比如插件宿主),它的行为就不可靠了。
- 不要和
Application.ExecutablePath混淆:ExecutablePath返回完整文件路径(含 .exe 名),StartupPath是其父目录 - 在 ClickOnce 部署下,它指向客户端缓存的应用版本目录,不是原始发布服务器路径
- 如果你只是读写本地配置文件,优先用
BaseDirectory,别依赖 WinForms 特有 API 增加耦合
路径拼接必须用 Path.Combine,别拼字符串
拿到根路径后,几乎所有后续操作(读配置、写日志、加载资源)都要拼子路径。硬连 baseDir + "\config.json" 或 baseDir + "/config.json" 是跨平台灾难的起点。
Path.Combine() 不仅自动处理正斜杠/反斜杠,还能正确归一化空段、.. 和 .,避免生成非法路径。
- 错误写法:
Path.Combine(baseDir, "logs", DateTime.Today.ToString("yyyy-MM-dd") + ".log")—— 如果baseDir末尾已有分隔符,Combine会自动去重,安全 - 危险写法:
baseDir + @"logs" + fileName—— Windows 下看似能跑,Linux/macOS 直接报DirectoryNotFoundException - 注意
Path.Combine不验证路径是否存在,也不创建目录。写文件前记得先Directory.CreateDirectory()
真正容易被忽略的点是:路径语义本身在不同部署形态下就不同。开发时看到的 binDebug,CI 构建后是 publish,Docker 里可能是 /app/,而 Azure App Service 又藏在 D:homesitewwwroot。别写死任何路径假设,所有路径访问都应基于运行时动态获取的基目录,并做好不存在时的 fallback 或明确报错。










