基于 JSON 配置的 .NET 桌面应用自动更新实现指南
在现代桌面应用开发中,自动更新能力已成为提升用户体验和保障软件安全的关键功能。对于使用 .NET(如 WinForms、WPF 或 MAUI)构建的 Windows 桌面应用,通过轻量级的 JSON 配置文件驱动更新逻辑,是一种灵活、可维护且易于部署的方案。本文将详细介绍如何设计并实现一个基于 JSON 配置的自动更新系统。
一、方案设计思路
我们的目标是:无需依赖复杂框架(如 Squirrel、ClickOnce),仅通过 HTTP 请求 + JSON 配置 + 简单下载逻辑,实现版本检测与增量/全量更新。
核心组件包括:
- 远程 JSON 配置文件:托管在服务器或 CDN 上,描述最新版本信息。
- 本地版本管理:读取当前应用版本(通常来自
AssemblyVersion)。 - 更新检查器:对比本地与远程版本,判断是否需要更新。
- 下载与安装模块:下载新版本安装包,并启动更新流程(如替换文件或运行安装程序)。
- 用户交互界面(可选):提示用户有新版本可用。
二、JSON 配置文件结构
在服务器上维护一个公开可访问的 update.json 文件,例如:
{
"version": "2.1.0",
"releaseNotes": "修复了若干稳定性问题,新增深色主题支持。",
"downloadUrl": "https://example.com/app/myapp-v2.1.0.exe",
"mandatory": false,
"minSupportedVersion": "1.0.0"
}
字段说明:
version:语义化版本号(SemVer),用于版本比较。downloadUrl:新版本安装包或 ZIP 包的下载地址。releaseNotes:更新日志,用于展示给用户。mandatory:是否强制更新(如存在严重安全漏洞)。minSupportedVersion:最低支持版本,用于判断是否需跳过多个版本。
三、读取本地应用版本
在 .NET 中,可通过以下方式获取当前程序集版本:
var currentVersion = Assembly.GetExecutingAssembly()
.GetName().Version?.ToString() ?? "1.0.0";
💡 建议使用
[assembly: AssemblyVersion("2.1.0")]在AssemblyInfo.cs中显式指定版本,或通过项目文件<Version>属性控制。
四、实现更新检查逻辑
1. 定义更新信息模型
public class UpdateInfo
{
public string Version { get; set; } = string.Empty;
public string DownloadUrl { get; set; } = string.Empty;
public string ReleaseNotes { get; set; } = string.Empty;
public bool Mandatory { get; set; }
public string MinSupportedVersion { get; set; } = "0.0.0";
}
2. 从远程加载 JSON 并解析
private async Task<UpdateInfo?> CheckForUpdateAsync(string updateUrl)
{
try
{
using var client = new HttpClient();
var json = await client.GetStringAsync(updateUrl);
return JsonSerializer.Deserialize<UpdateInfo>(json);
}
catch (Exception ex)
{
// 记录日志:无法获取更新信息
Console.WriteLine($"Update check failed: {ex.Message}");
return null;
}
}
3. 版本比较
使用 Version 类进行语义化比较:
bool IsNewerVersion(string current, string latest)
{
return Version.TryParse(current, out var v1) &&
Version.TryParse(latest, out var v2) &&
v2 > v1;
}
⚠️ 注意:
Version类要求格式为x.x[.x[.x]],不支持-beta等后缀。若需完整 SemVer 支持,可引入 Semver NuGet 包。
五、执行更新流程
方案 A:下载安装程序并启动(推荐)
适用于 .exe 或 .msi 安装包:
private async Task DownloadAndInstallAsync(string downloadUrl)
{
var tempFile = Path.Combine(Path.GetTempPath(), "MyApp_Update.exe");
using var client = new HttpClient();
using var stream = await client.GetStreamAsync(downloadUrl);
using var fileStream = File.Create(tempFile);
await stream.CopyToAsync(fileStream);
// 启动安装程序,并退出当前应用
Process.Start(new ProcessStartInfo
{
FileName = tempFile,
UseShellExecute = true
});
Application.Current.Shutdown(); // WPF
// 或 Application.Exit(); // WinForms
}
方案 B:解压 ZIP 替换文件(无安装程序场景)
适用于绿色版应用:
- 下载 ZIP 包;
- 关闭主程序;
- 启动一个独立的“更新器”进程(避免文件被占用);
- 更新器解压 ZIP 到应用目录,再重启主程序。
🔒 安全提示:务必验证下载内容的完整性(如 SHA256 校验),防止中间人攻击。
六、集成到应用生命周期
在应用启动时(或定期后台任务)触发检查:
// WPF 示例:App.xaml.cs
protected override async void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var updateInfo = await CheckForUpdateAsync("https://example.com/update.json");
if (updateInfo != null && IsNewerVersion(GetCurrentVersion(), updateInfo.Version))
{
var result = MessageBox.Show(
$"发现新版本 {updateInfo.Version}!\n{updateInfo.ReleaseNotes}\n\n是否立即更新?",
"更新可用",
MessageBoxButton.YesNo);
if (result == MessageBoxResult.Yes)
{
await DownloadAndInstallAsync(updateInfo.DownloadUrl);
}
}
}
七、增强建议
- 缓存机制:避免每次启动都请求,可记录上次检查时间(如 24 小时内不再检查)。
- HTTPS 强制:确保
update.json和安装包通过 HTTPS 提供。 - 数字签名验证:对安装包进行 Authenticode 签名,提升安全性。
- 静默更新(可选) :后台下载,下次启动时自动应用。
- 回滚机制:保留旧版本备份,更新失败可恢复。
八、总结
通过一个简单的 JSON 配置文件,配合 .NET 内置的 HTTP、JSON 和进程管理能力,我们可以快速构建一个轻量、可控、跨 .NET 桌面平台的自动更新系统。该方案无需外部依赖,易于调试和部署,特别适合中小型项目或对更新流程有定制需求的场景。
📌 最佳实践:将更新逻辑封装为独立类库(如
MyApp.Updater),便于复用和测试。
随着 .NET 生态的演进,未来也可考虑与 MSIX 打包结合,但基于 JSON 的方案因其简单性和通用性,仍具有不可替代的价值。