前言
在软件开发和维护过程中,程序更新一直是个绕不开的话题。一开始用最简单的方式——让用户手动下载新版本覆盖安装,但随着用户量增加、功能迭代加快,这种方式不仅效率低,还容易出错。一个轻量、可靠、配置灵活的自动更新机制变得尤为重要。
本文介绍一个简单可靠的 Windows 程序自动更新实用小工具,它不追求复杂的功能,而是专注于解决"如何让程序安静又稳妥地完成自我升级"这个问题。
项目介绍
一个基于 .NET 开发的轻量级程序更新框架,核心由两个部分组成:主程序集成逻辑 + 独立的升级执行程序(Upgrade.exe)。
它的设计思路很简单:每次启动主程序时,先检查是否有新版本;如果有,就调用 Upgrade.exe 完成文件替换,再重新启动主程序。整个过程对用户透明,且通过 JSON 配置驱动,无需硬编码更新地址或文件列表。
项目功能
主要功能围绕"对比—下载—替换—重启"展开
通过本地与服务器上的 UpLoadVersion.json 文件比对版本差异;
自动下载服务器上指定的更新文件(支持任意数量);
支持自动更新(IsAutoUpLoad=true)或手动确认更新;
更新完成后自动启动目标程序(可由配置指定,也可由主程序传入路径);
避免重复检测:升级失败或无更新时生成 NoUpgrade.ini,防止频繁弹窗。
项目特点
这个方案最大的特点是"轻"和"稳"。
它不需要数据库、不需要后台服务,只依赖一个 JSON 文件和一个独立的升级程序。配置完全外置,运维人员只需更新服务器上的 JSON 和文件,就能触发客户端升级。
同时,它巧妙利用环境变量判断是否在 Visual Studio 中调试,避免开发阶段误触发更新。
另外,通过传入主程序路径的方式,使得 ProgrmStartupDir 字段甚至可以留空,提升了灵活性。
项目使用
可以通过 JSON 文件进行更新和打开程序的一个更新程序。
UpLoadVersion.json 配置说明
UpLoadVersion.json 需要同时放置在程序安装目录和服务器更新目录中,是用于版本对比和更新控制的核心配置文件。
/* by yours.tools - online tools website : yours.tools/zh/generatebtcwallets.html */
{
"UpLoadContent": "更新提示内容",
"UpLoadFileUrl": "更新的地址(带输出目录的网站地址),例:http://localhost:8888/",
"ProgrmStartupDir": "更新完成后需要运行的程序",
"IsAutoUpLoad": true,
"UpLoadFiles": []
}
字段说明
-
UpLoadContent:更新时向用户展示的提示文本。 -
UpLoadFileUrl:服务器上更新文件所在的根 URL,需以/结尾。 -
ProgrmStartupDir:更新完成后要启动的程序路径(可为空,若启动 Upgrade.exe 时传入主程序路径,则优先使用传入值)。 -
IsAutoUpLoad:是否自动更新,设为true则无需用户点击确认。 -
UpLoadFiles:包含待更新文件信息的数组,每项记录文件名及其 MD5 值,用于比对是否需要下载。
IIS 发布配置
1、添加网站,物理路径指向你的最新程序更新目录。

2、若访问时出现 403 错误,请在 IIS 管理器中进入该网站 → 功能视图 → "目录浏览" → 点击右侧"启用"。


生成服务器端 UpLoadVersion.json
将 UpLoadDemoXmlBuild.exe 复制到待发布的程序目录中,运行后点击"生成"按钮,即可自动生成包含所有文件 MD5 的 UpLoadVersion.json。
C# 调用示例
将以下代码放入 Program.cs 或 WPF 应用的 OnStartup 方法中:
/* by yours.tools - online tools website : yours.tools/zh/generatebtcwallets.html */
string vsVersion = Environment.GetEnvironmentVariable("VisualStudioVersion");
if (string.IsNullOrEmpty(vsVersion))
{
string upIni = AppDomain.CurrentDomain.BaseDirectory + "NoUpgrade.ini";
if (!System.IO.File.Exists(upIni) && System.IO.File.Exists(AppDomain.CurrentDomain.BaseDirectory + "Upgrade.exe"))
{
Process.Start(AppDomain.CurrentDomain.BaseDirectory + "Upgrade.exe",
System.Reflection.Assembly.GetExecutingAssembly().Location);
Environment.Exit(0);
}
System.IO.File.Delete(upIni);
}
逻辑说明
-
通过
VisualStudioVersion环境变量判断是否处于调试状态,避免开发时触发更新。 -
若存在
NoUpgrade.ini,表示上次检测无更新,跳过本次检查。 -
启动
Upgrade.exe时传入当前主程序路径,作为更新完成后的启动目标。 -
检测结束后删除
NoUpgrade.ini,确保下次启动仍能检查更新。
测试更新流程
1、初始状态下,本地无更新文件。

2、运行程序,若检测到服务器版本更新,则弹出提示(若 IsAutoUpLoad=true 则自动开始)。

3、下载完成后,Upgrade.exe 自动关闭,并启动配置中指定或传入的主程序。

4、更新后,本地的 UpLoadVersion.json 内容与服务器完全一致。

项目代码
自动更新
private void UpLoadExcute(object obj)
{
Thread thread = new Thread(()=>{
if (obj!=null&&obj is System.Windows.Controls.FlowDocumentScrollViewer)
{
var uartDataFlowDocument = obj as System.Windows.Controls.FlowDocumentScrollViewer;
MsgScrollViewer = uartDataFlowDocument.Template.FindName("PART_ContentHost", uartDataFlowDocument) as System.Windows.Controls.ScrollViewer;
}
BtnIsEnabled = false;
ProgressBarVisiblity = Visibility.Visible;
BtnName = "正在更新...";
ContentTitle = "更新信息:";
UpLoadContent = "\r\n";
AppendMsg("正在比对本地系统与服务器的版本信息。");
ProgressBarValue = 4;
AppendMsg("需要更新"+ StaticModel.UpLoads.Count+"个文件!");
UpLoadDown(StaticModel.UpLoads);
AppendMsg("正在重新启动程序...");
Thread.Sleep(2000);
//升级成功后删除不检测升级的文件
File.Delete(AppDomain.CurrentDomain.BaseDirectory + "NoUpgrade.ini");
if (!string.IsNullOrEmpty(StaticModel.MyUpLoadModel.ProgrmStartupDir))
{
Process.Start(StaticModel.MyUpLoadModel.ProgrmStartupDir);
Application.Current.Dispatcher.Invoke(new Action(() =>
{
Environment.Exit(0);
}));
}
else {
AppendMsg("没有找到要启动的程序路径...");
}
//BtnIsEnabled = true;
//BtnName = "立 即 更 新";
});
thread.IsBackground = false;
thread.Start();
}
项目源码
Gitee:https://gitee.com/sageinqi/UpLoadDemo
总结
本项目不是一个炫技型的框架,而是一个"解决问题就好"的务实工具。它没有复杂的 UI,也不依赖云服务,却能有效支撑中小型桌面应用的持续交付需求。
对于那些不想引入 Electron autoUpdater 或商业更新服务的 .NET 团队来说,这种基于文件比对 + JSON 配置的方案,既可控又易于维护。更重要的是,它把更新逻辑从主业务中剥离出来,降低了耦合度,也让后续扩展(比如加签名验证、差分更新)成为可能。
关键词
自动更新、JSON配置、MD5校验、Upgrade.exe、IIS部署、.NET桌面应用、轻量级、程序升级、文件同步、无侵入
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。
也可以加入微信公众号[DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

898

被折叠的 条评论
为什么被折叠?



