单文件打包 .NET 程序的完整方案:ILRepack + 发布脚本
约 1 分钟· 621 字 98 次阅读
做桌面工具的人大概率会遇到同一个问题:程序写好了,但交付物是一堆 DLL 散文件,发给用户要么缺文件要么版本错乱。单文件打包是解决这个问题的标准姿势,本文基于一套 WPF/C# 工具箱的实践经验展开。
为什么用 ILRepack
.NET Framework 4.8 项目没有官方的一键单文件发布(那是 .NET Core/5+ 才有的),社区主流方案是 ILRepack——把多个托管程序集合并成一个。
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.34.2" />
装上之后可以在 csproj 里配置 AfterBuild 目标,也可以在发布脚本里手动调用,后者更可控。
发布脚本的设计
推荐用 PowerShell 脚本(build-release.ps1)串起整个流程,而不是依赖 IDE 菜单:
param(
[string]$Configuration = "Release",
[string]$OutputDir = "dist"
)
# 1. 编译
dotnet build -c $Configuration
# 2. 合并程序集(排除主程序集本身)
& ilrepack /lib:"bin\$Configuration" `
/out:"$OutputDir\Tool.exe" `
"bin\$Configuration\Tool.exe" `
"bin\$Configuration\*.dll"
# 3. 拷贝原生依赖(比如 SQLite、OpenCV 的 native 库)
Copy-Item "bin\$Configuration\native\*" "$OutputDir\" -Recurse
# 4. 产物校验:文件数应为 1(托管)+ N(原生)
Get-ChildItem $OutputDir | Select Name, Length
常见坑
| 问题 | 原因与解法 |
|---|---|
合并后启动报 FileNotFound |
有程序集没被合并(动态加载或延迟绑定)→ 检查 App.config 的 probing 路径,或把这些 DLL 加入合并列表 |
| 泛型/反射失效 | 某些库(如 NHibernate)依赖独立程序集边界 → 用 --internalize 前先测功能 |
| 配置文件丢失 | .config 不算程序集,要单独拷贝 |
| 图标/资源文件 | WinForms/WPF 资源在 exe 里没问题,但独立资源文件要手动带上 |
打包前的日志检查
一个容易被忽略的环节:发布前检查代码里残留的调试日志。团队的做法是在发布脚本里加一道静态检查:
# 拒绝包含 Console.WriteLine / Debug.WriteLine 的发布
$violations = Select-String -Path "src\*.cs" -Pattern "Console\.WriteLine|Debug\.WriteLine"
if ($violations) {
Write-Error "发布前请清理调试日志: $($violations.Count) 处"
exit 1
}
这比靠自觉可靠得多——CI 或发布脚本会自动拦截。
小结
- 托管程序集 → ILRepack 合并成单 exe;
- 原生依赖 → 目录结构保留,独立分发;
- 发布流程 → 脚本化(编译 → 合并 → 拷贝 → 校验 → 日志检查);
- 每次发布前打 git tag 存档,方便回滚。
单文件不只是"好看",它把"用户缺 DLL"这类支持成本直接降为零。