探秘Upgrade.Net:你的.NET项目自动化升级利器

一个精心设计的自动化升级方案,比你想象的重要得多。


作为一名 .NET 开发者,你一定经历过这样的场景:产品迭代了十几个版本,每次都要手动打包、发给客户、远程指导覆盖文件、解压、替换,稍有不慎就搞出生产事故来。客户在群里一阵狂轰滥炸,你只能一边道歉一边排查。

更别提当你面对的是数十个甚至上百个客户端时,那简直就是运维的噩梦。

Upgrade.Net 正是为终结这种痛苦而生的一款轻量级开源组件。今天我们就来深入拆解它,看看这个基于 .NET 10 打造的自动化升级方案,是如何将复杂的升级流程化繁为简的。


一、Upgrade.Net 是什么?

Upgrade.Net 是一个基于 .NET 的 Windows 应用自动化升级解决方案,采用 MIT 开源协议,目前托管在 Gitee 上。

它不是那种"大而全"的庞然大物,而是精准聚焦在一个痛点场景:让你的桌面应用能够自动从远程服务器下载更新包,解压、备份、替换文件,然后无缝启动新版本

讲得直白一点——你的客户端应用集成了它之后,升级这件事基本就不再需要人工介入了。

核心设计理念

Upgrade.Net 的聪明之处在于,它把升级这件事抽象成了「步骤 + 操作」的模型:

  • 步骤(Step):升级流程中的一个个节点,比如"下载更新包"、"备份旧文件"、"解压覆盖"。
  • 操作(Option):每个步骤具体执行的动作,共计 16 种内置操作类型。

你只需要写一个 JSON 配置文件,定义好步骤序列,剩下的全部交给引擎自动执行。这种声明式的配置方式,意味着不需要改一行代码就能调整升级流程


二、架构拆解:三大模块各司其职

Upgrade.Net 采用了教科书级别的模块化设计,整个项目被拆成三个独立组件:

Upgrade.Net.slnx
├── Upgrade.Net/          # 核心类库
├── Upgrade.Cmd/          # 控制台版本
└── Upgrade.Wpf/          # WPF 桌面版本

2.1 Upgrade.Net — 核心引擎

这是整个项目的灵魂。它负责:

  • 配置解析:读取 JSON 配置文件,反序列化为 StepConfig 对象数组;
  • 策略执行:每个步骤根据 Option 字段创建对应的 UpgradeAction,采用策略模式调度;
  • 状态管理:通过 UpgradeView 接口向外层(控制台或 WPF)推送执行状态;
  • 异常处理:内置重试机制、continueOnError 容错开关、自定义等待时间。

一套核心引擎同时驱动两套完全不同的 UI 界面,靠的就是 UpgradeView 这个接口的抽象能力——这在对设计模式的应用上是相当干净的。

2.2 Upgrade.Cmd — 控制台版

适合集成到 CI/CD 流水线、后台静默升级、或者不需要图形界面的轻量场景。执行一个命令,升级过程自动跑完,终端输出完整日志。

2.3 Upgrade.Wpf — 桌面版

面向最终用户的图形界面方案。采用了 MVVM 架构,无边框窗口设计搭配中国蓝主题,颜值在线。支持:

  • 实时进度条和状态信息展示;
  • 下载的暂停 / 继续 / 取消交互;
  • 升级步骤可视化列表;
  • 版本更新日志滚动展示。

两个 UI 版本共享同一套核心逻辑,这种「一个引擎,两套壳」的设计,对于需要同时覆盖技术用户和普通用户的团队来说,非常务实。


三、界面一览:两种风格,同样优雅

说再多不如眼见为实。来看看 Upgrade.Net 实际运行时的样子。

WPF 桌面版

WPF 版本采用了无边框窗口 + 中国蓝主题的设计语言,界面简洁大方,适合面向终端用户的场景。

开始界面 — 清晰的标题、版本信息和步骤概览,让用户一眼就知道即将发生什么:

WPF 开始界面

升级进行中 — 实时进度条、当前步骤高亮、状态标签一目了然,支持暂停/继续/取消:

WPF 升级界面

升级完成 — 所有步骤打上勾,提示即将启动新版本,体验闭环:

WPF 完成界面

控制台版

控制台版本则走极简路线,终端信息密度高,适合集成到自动化流水线或服务器后台场景。

开始界面 — 纯文本版升级信息,附带 ASCII 进度条:

控制台开始界面

升级进行中 — 每个步骤的执行状态实时输出,日志清晰可追溯:

控制台升级界面

升级完成 — 全部步骤通过,自动退出:

控制台完成界面

两种界面风格覆盖了从「普通用户」到「运维人员」的全场景,选哪个完全取决于你的目标受众。


四、16 种操作类型:一个配置搞定一切

这是 Upgrade.Net 最让我眼前一亮的设计。它把升级过程中可能用到的所有原子操作拆成了 16 种内置类型:

操作类型 用途 典型场景
Download 从 URL 下载文件 拉取远程更新包
Command 执行命令行(同步等待) 执行数据库迁移脚本
Launch 启动外部程序(异步) 升级后启动主程序
Zip 压缩文件/目录 生成日志归档
Unzip 解压文件 解压更新包
MoveDir / MoveDoc 移动目录/文件 迁移旧数据
CopyDir / CopyDoc 复制目录/文件 复制配置文件
CreateDir / CreateDoc 创建目录/文件 创建运行时需要的目录
DeleteDir / DeleteDoc 删除目录/文件 清理临时文件
RenameDir / RenameDoc 更名目录/文件 备份旧版本

几乎覆盖了应用升级中你能想到的所有文件系统操作。每一个步骤还可以独立配置:

  • waitTime:执行后等待时间,支持倒计时显示——比如"更新将在 5 秒后重启";
  • retryCount + retryDelay:重试次数和延迟——网络抖动?自动重试;
  • continueOnError:失败是否继续——非关键步骤出错不阻断整体流程。

这种颗粒度的掌控力,让你可以像搭积木一样自由编排升级流程,而不是被框架的固定流程框死。


五、配置文件:声明式编排的艺术

来看看一个典型的升级配置长什么样:

{
  "icon": "logo.ico",
  "title": "MyApp 升级程序",
  "oldVersion": "1.0.0",
  "newVersion": "2.0.0",
  "autoStart": true,
  "autoClose": true,
  "showSteps": true,
  "verInfo": "本次更新:\n- 修复了数据导出 Bug\n- 新增报表模块\n- 优化内存占用",
  "steps": [
    {
      "title": "下载更新包",
      "description": "正在从服务器获取最新版本...",
      "option": "Download",
      "url": "https://cdn.example.com/releases/v2.0.0.zip",
      "file": "update.zip",
      "retryCount": 3,
      "retryDelay": 2000
    },
    {
      "title": "备份当前版本",
      "description": "正在备份现有文件以防意外...",
      "option": "CopyDir",
      "source": "./app",
      "destination": "./backup/1.0.0"
    },
    {
      "title": "解压更新包",
      "description": "正在解压新版本文件...",
      "option": "Unzip",
      "source": "update.zip",
      "destination": "./app",
      "overwrite": true
    },
    {
      "title": "清理安装包",
      "description": "正在清理临时文件...",
      "option": "DeleteDoc",
      "path": "update.zip"
    },
    {
      "title": "启动新版本",
      "description": "即将启动 MyApp v2.0.0",
      "option": "Launch",
      "command": "dotnet",
      "args": "MyApp.dll",
      "path": "./app",
      "waitTime": 3
    }
  ]
}

配置即文档——任何一个运维人员甚至客户自己,不需要懂 C#,打开 JSON 文件就能看懂升级流程在干什么。这种声明式配置带来的可维护性提升,远胜于把流程硬编码在代码里。


六、技术栈解析:做了哪些正确的选择

5.1 .NET 10 — 激进的版本策略

Upgrade.Net 直接上了 .NET 10.0,这在当下的 .NET 生态中属于相当激进的选择。带来的好处是:原生 AOT 编译的潜力、JsonSerializer 源生成器的极致性能、以及跨平台能力的基础支撑。

5.2 HttpClient 静态复用

核心类库中对 HttpClient 采用的是静态单例复用而非每次 new——这是处理网络请求的经典最佳实践。如果你曾经被 TIME_WAIT 端口耗尽问题折磨过,会明白这个细节有多重要。

5.3 策略模式 + MVVM

设计模式上,操作执行采用了策略模式——每个 UpgradeOption 枚举值对应一个具体的 UpgradeAction 子类,扩展新操作只需新增枚举和实现类即可,完全符合开闭原则。UI 层则是标准的 MVVM 分离,View 和 ViewModel 通过接口解耦,可测试性和可维护性都有保障。

5.4 Windows 7+ 兼容

更难得的是,项目明确声明了支持 Windows 7 及以上系统。很多现代化开源工具默认放弃了对 Win7 的兼容,但对于仍有大量 Win7 客户的 toB 软件来说,这个细节意味着你可以放心地集成 Upgrade.Net 而不必担心客户端的系统版本问题。


七、实战集成:三步让你的应用具备自升级能力

第一步:引入 Upgrade.Net 核心库

克隆仓库或将核心类库添加到你的解决方案中。如果你的主程序已经是一个 .NET 项目,集成几乎零成本——直接项目引用即可。

第二步:编写升级配置文件

参照上面的配置示例,根据你的项目实际情况编写 upgrade.json

  • 设置图标、标题、版本信息;
  • 编排步骤序列——下载 → 备份 → 解压 → 启动是标准四步;
  • 根据网络环境调整重试参数。

第三步:在你的主程序中触发升级

在你应用的"检查更新"入口处,启动 Upgrade.Cmd 或 Upgrade.Wpf:

// 简单粗暴的方式:直接拉起升级程序
Process.Start("Upgrade.Wpf.exe");
// 然后退出当前进程
Application.Current.Shutdown();

剩下的——下载、备份、解压、覆盖、重启——全部由 Upgrade.Net 自动完成。


八、值得关注的细节与使用建议

在使用过程中,有几个经验点值得留意:

  1. 升级程序与主程序分离执行。这是基本原则——升级器必须独立于被升级的程序运行,否则你无法覆盖正在使用的文件。Upgrade.Net 把这个理念贯穿到了设计里。

  2. 充分利用备份机制。强烈建议在任何覆盖操作之前先 CopyDir 备份当前版本。多写一步配置,省去一万次回滚的麻烦。

  3. 控制台版适合 CI/CD 集成。如果你有自己的构建流水线,可以把 Upgrade.Cmd 集成进去,实现"构建完自动推送到客户端并触发升级"的闭环。

  4. WPF 版的交互设计值得参考。暂停/继续/取消的下载交互、步骤状态的四色标识(等待/执行中/完成/失败),这些细节让用户对升级进度一目了然,不再是看着一根进度条尬等。

  5. continueOnError 的使用要审慎。非关键步骤(如清理临时文件)可以设为 true 以防阻塞流程,但关键步骤(如文件覆盖)务必让其失败时中断,避免产生半升级的不一致状态。


九、总结

在.NET 桌面应用开发中,自动升级能力往往是最容易被低估的功能——直到你真正需要它的时候,才发现自己缺了一条腿。

Upgrade.Net 的价值不在于它用了多么高深的技术,而在于它用简洁的设计覆盖了真实场景中最繁琐的那部分工作。16 种原子操作覆盖了文件系统操作的全集,策略模式保证了扩展性,JSON 配置实现了零代码编排,两套 UI 适配了不同用户群体——每一处设计都直击痛点。

对于那些需要向客户分发桌面客户端的 .NET 团队来说,Upgrade.Net 几乎是一个开箱即用的升级基础设施。花半小时配好一份 upgrade.json,从此告别手动拷贝文件的运维噩梦。

开源地址:https://gitee.com/leadiot/upgrade.net

如果你觉得它有用,不妨给作者点个 Star,你的每一次认可,都是开源社区持续进步的动力。

posted @ 2026-07-15 20:58  花香幽暖  阅读(8)  评论(0)    收藏  举报