WinForms 学习笔记(七):部署——ClickOnce、单文件发布与自动更新

写在前面

承接篇6。本篇讲 WinForms 应用怎么打包交付给用户:单文件发布、ClickOnce、自动更新、签名。

WinForms 部署比 Web 复杂:你要把 exe + 依赖装到用户机器、管更新、过 SmartScreen。.NET 8 时代,单文件发布 + ClickOnce 是主力,MSIX 是新选择。


一、dotnet publish:单文件发布

.NET SDK 的 dotnet publish 把应用打包成可分发的产物。最实用的是单文件(self-contained exe,用户机器不用装 .NET):

1
2
3
dotnet publish -c Release -r win-x64 --self-contained true \
  -p:PublishSingleFile=true \
  -p:IncludeNativeLibrariesForSelfExtract=true

参数:

参数含义
-c ReleaseRelease 编译
-r win-x64目标运行时(WinForms 只能 win-x64/x86)
--self-contained true自包含(带 .NET 运行时,用户免装)
PublishSingleFile打成单个 exe
IncludeNativeLibrariesForSelfExtract原生库也塞进单文件
1
2
3
产物:bin/Release/net8.0-windows/win-x64/publish/MyApp.exe
  → 一个文件(运行时解压到临时目录),双击即跑
  → 拷给用户、放共享盘、U 盘分发都行

自包含单文件约 150MB+(含 .NET 运行时)。要更小用 --self-contained false(框架依赖,~1MB,但用户机器要装 .NET Desktop Runtime)。


二、ReadyToRun / Trim

ReadyToRun(R2R):预编译成原生机器码,启动更快,体积大些:

1
2
dotnet publish -c Release -r win-x64 --self-contained true \
  -p:PublishSingleFile=true -p:PublishReadyToRun=true
1
2
3
4
ReadyToRun:
  预 JIT 成原生码,启动快 ~20-30%
  体积大 ~30%
  → 启动敏感的工具类应用值得开

Trim(裁剪):移除没用到的代码,减小体积。WinForms 对 Trim 支持差(大量反射 + 设计器),别开:

1
2
# WinForms 别开 Trim(会运行时缺类型崩)
-p:PublishTrimmed=true   # ✗ WinForms 不推荐

WinForms 还不能完全 AOT(NativeAOT),反射 / 设计器 / 资源加载不兼容。要做原生编译,考虑迁 MAUI/WinUI。


三、ClickOnce:老牌自动更新

ClickOnce(.NET Framework 2.0 起)是 WinForms/WPF 的"零摩擦安装 + 自动更新"方案:用户点网页链接 → 装到用户目录(不需管理员)→ 每次启动检查更新。

.NET 8 下 ClickOnce 仍支持(VS 项目属性 → Publish,或 publish 配置),流程:

1
2
3
4
1. dotnet publish 生成 ClickOnce 清单(.application / .manifest)
2. 放到 Web 服务器 / 共享盘 / Azure Blob
3. 用户访问 install.htm → 下载安装
4. 程序每次启动检查更新 → 有新版自动下载替换

VS 里:项目属性 → Publish → ClickOnce 发布向导,设发布位置、更新策略(启动时检查 / 间隔 N 天)、签名。

1
2
3
4
5
ClickOnce 适合:
  ✓ 企业内部工具(用户点链接即装,自动更新,不需管理员权限)
  ✓ 频繁更新的小工具
  ✗ 需要系统服务 / 驱动 / 深度注册表的(ClickOnce 沙箱限制)
  ✗ 需要"商店分发"的现代场景(用 MSIX)

ClickOnce 的更新是"替换整个应用",大应用更新慢;但它仍是 WinForms 内网分发的最省心方案。


四、MSIX:现代打包

MSIX(Windows 10+)是微软主推的现代应用包格式:干净安装/卸载、沙箱、商店分发、自动更新。

1
2
3
4
5
6
MSIX vs ClickOnce:
  MSIX      现代包格式,干净安装,商店分发,需打包工程
  ClickOnce 老牌,零摩擦,内网/网页分发,更新简单

  → 想进 Microsoft Store / 企业私店 → MSIX
  → 内网快速分发 + 自动更新 → ClickOnce 够用

打包用 Visual Studio 的"Windows 应用程序打包项目"(WAP)或 MakeAppx 工具。MSIX 要签名(证书),企业分发用内部 CA,商店分发用 MS Store 关联。


五、自动更新实现

不用 ClickOnce/MSIX,自己实现"启动时检查 + 下载 + 替换":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 简化版自动更新
private async void Form1_Load(object sender, EventArgs e)
{
    var latest = await CheckLatestVersionAsync();
    if (latest.Version > CurrentVersion)
    {
        if (MessageBox.Show($"发现新版本 {latest.Version},更新?",
            "更新", MessageBoxButtons.YesNo) == DialogResult.Yes)
        {
            await DownloadAndUpdateAsync(latest.Url);
            Application.Restart();   // 重启加载新版本
        }
    }
}

要点:

  • 版本号放一个可访问的地方(API/文件),启动时拉取对比。
  • 下载新 exe 到临时目录,替换主程序(可能需 bat 脚本辅助,运行中的 exe 不能直接覆盖)。
  • 用 ClickOnce/MSIX 省事;自实现适合特殊场景。

开源方案:Velopack、Squirrel.Windows,封装了检查/下载/替换/快捷方式全套。


六、代码签名

Windows SmartScreen 对未签名 exe 会弹警告(蓝屏"Windows 已保护你的电脑")。企业/正式分发必须签名

1
2
3
4
签名方式:
  代码签名证书(EV / OV+ signtool.exe
  EV 证书  立即过 SmartScreen(贵,要硬件 token
  OV 证书  需积累信誉,初期仍弹 SmartScreen
1
2
signtool sign /fd sha256 /a /tr http://timestamp.sectigo.com /td sha256 \
  /n "Your Company Name" MyApp.exe

内部分发用自签名证书(企业 CA 推到用户机器的根证书);公网分发用商业代码签名证书。


七、部署选型

1
2
3
4
5
6
7
8
你的场景                              推荐
──────────────────────────────────────────────────────
个人/小工具,拷给朋友                  单文件 exe(U 盘/网盘)
企业内部,频繁更新                     ClickOnce(网页/共享盘 + 自动更新)
进 Microsoft Store / 企业私店         MSIX
要启动快                              单文件 + ReadyToRun
要正式分发,过 SmartScreen             商业代码签名 + 单文件/MSIX
自动更新不想自己造                     Velopack / Squirrel

八、小结

1
2
3
4
5
6
7
WinForms 部署核心:
  ✓ dotnet publish --self-contained + PublishSingleFile = 单 exe 分发
  ✓ ReadyToRun 加速启动(体积换启动);Trim 别开
  ✓ ClickOnce:内网零摩擦安装 + 自动更新(最省心)
  ✓ MSIX:现代包,适合商店/企业私店
  ✓ 自动更新:ClickOnce/MSIX 自带;或 Velopack/Squirrel
  ✓ 正式分发必须代码签名(过 SmartScreen)

下一篇:WinForms vs WPF——两个框架对照、选型决策、迁移路径,系列收官。