基于 JSON 配置的 .NET 桌面应用自动更新实现指南

基于 JSON 配置的 .NET 桌面应用自动更新实现指南

在现代桌面应用开发中,自动更新能力已成为提升用户体验和保障软件安全的关键功能。对于使用 .NET(如 WinForms、WPF 或 MAUI)构建的 Windows 桌面应用,通过轻量级的 JSON 配置文件驱动更新逻辑,是一种灵活、可维护且易于部署的方案。本文将详细介绍如何设计并实现一个基于 JSON 配置的自动更新系统。


一、方案设计思路

我们的目标是:无需依赖复杂框架(如 Squirrel、ClickOnce),仅通过 HTTP 请求 + JSON 配置 + 简单下载逻辑,实现版本检测与增量/全量更新

核心组件包括:

  1. 远程 JSON 配置文件:托管在服务器或 CDN 上,描述最新版本信息。
  2. 本地版本管理 :读取当前应用版本(通常来自 AssemblyVersion)。
  3. 更新检查器:对比本地与远程版本,判断是否需要更新。
  4. 下载与安装模块:下载新版本安装包,并启动更新流程(如替换文件或运行安装程序)。
  5. 用户交互界面(可选):提示用户有新版本可用。

二、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 替换文件(无安装程序场景)

适用于绿色版应用:

  1. 下载 ZIP 包;
  2. 关闭主程序;
  3. 启动一个独立的"更新器"进程(避免文件被占用);
  4. 更新器解压 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);
        }
    }
}

七、增强建议

  1. 缓存机制:避免每次启动都请求,可记录上次检查时间(如 24 小时内不再检查)。
  2. HTTPS 强制 :确保 update.json 和安装包通过 HTTPS 提供。
  3. 数字签名验证:对安装包进行 Authenticode 签名,提升安全性。
  4. 静默更新(可选):后台下载,下次启动时自动应用。
  5. 回滚机制:保留旧版本备份,更新失败可恢复。

八、总结

通过一个简单的 JSON 配置文件,配合 .NET 内置的 HTTP、JSON 和进程管理能力,我们可以快速构建一个轻量、可控、跨 .NET 桌面平台的自动更新系统。该方案无需外部依赖,易于调试和部署,特别适合中小型项目或对更新流程有定制需求的场景。

📌 最佳实践 :将更新逻辑封装为独立类库(如 MyApp.Updater),便于复用和测试。

随着 .NET 生态的演进,未来也可考虑与 MSIX 打包结合,但基于 JSON 的方案因其简单性和通用性,仍具有不可替代的价值。

相关推荐
无风听海1 小时前
.NET 10 之dotnet run的功能
.net
岩屿1 小时前
Ubuntu下安装Docker并部署.NET API(二)
运维·docker·容器·.net
码云数智-大飞1 小时前
.NET 中高效实现 List 集合去重的多种方法详解
.net
easyboot2 小时前
使用tinyply.net保存ply格式点云
.net
张人玉2 小时前
WPF 多语言实现完整笔记(.NET 4.7.2)
笔记·.net·wpf·多语言实现·多语言适配
波波0071 天前
Native AOT 能改变什么?.NET 预编译技术深度剖析
开发语言·.net
Crazy Struggle2 天前
.NET 中如何快速实现 List 集合去重?
c#·.net
极客智造2 天前
ImageSharp 实战应用指南:.NET 跨平台图像处理落地实践
图像处理·.net
时光追逐者2 天前
一个基于 .NET + Vue 实现的通用权限管理平台(RBAC模式),前后端分离模式,开箱即用!
前端·vue.js·c#·.net·.net core