【手把手实战教学】基于C#和.NET Framework的WinForms开发教程系列(6)AutoUpdater.NET自动更新

【手把手实战教学】基于C#和.NET Framework的WinForms开发教程系列(6)AutoUpdater.NET 自动更新

系列目录
(1)Visual Studio 2026 中创建、运行、发布应用
(2)开机自启
(3)自动定时更新
(4)后台运行
(5)版本自增
(6)AutoUpdater.NET 自动更新


前言

开发环境:
IDE:Visual Studio 2026
语言:C#
框架:.NET Framework 4.5
UI:WinForms

在前面的文章中,我们让程序拥有了开机自启、定时任务、后台托盘等强大能力,并且通过自动生成脚本实现了版本号递增。但是,如果新版本只停留在开发者的电脑上,用户永远不会知道。如何让用户手中的软件自动检测并升级到最新版本,是商业软件必须要解决的问题。

本文将使用开源库 AutoUpdater.NET,仅需几十行代码,就能为你的 WinForms 程序添加强大的自动更新功能。
我们将从 NuGet 包的安装、服务器更新配置文件的准备,到程序中定时/手动检查更新的实现,一步步带你完成。

一、为什么需要自动更新?

传统的软件更新方式通常需要用户主动访问官网、下载安装包、卸载旧版本再安装新版本。这个过程不仅繁琐,而且用户往往因为嫌麻烦而停留在旧版本,导致 Bug 得不到修复、新功能无法触达,甚至引发兼容性问题。

有了自动更新后,程序可以在后台静默检查新版本,当发现更新时弹出友好的升级提示窗口,用户只需点击一下“更新”,程序就会自动下载并替换为新版本,整个过程无需离开软件界面,极大提升了用户体验和版本覆盖率。

二、实现原理

AutoUpdater.NET 是一个专门为 .NET WinForms / WPF 设计的自动更新组件,它的工作流程如下:

  1. 程序启动或定时触发时,向指定的 URL 请求一个 update.xml 文件。
  2. 解析 XML 中的最新版本号、下载地址、更新日志、是否强制更新等信息。
  3. 与当前程序版本(通过 InstalledVersion 属性设定)进行比较。
  4. 如果有新版本,弹出更新对话框,用户可以选择立即更新、稍后提醒或跳过;如果设置为强制更新,则用户不能跳过或关闭。
  5. 下载完成后,自动替换当前运行的程序文件(利用系统的文件移动特性),完成更新。

整个流程只需我们准备一个简单的 XML 文件和一个可访问的下载地址,程序内部调用其 API 即可。

三、实现步骤

1. 安装 NuGet 包

在“解决方案资源管理器”中右键项目 → “管理 NuGet 程序包”
在这里插入图片描述
搜索 Autoupdater,点击安装。
在这里插入图片描述
点击应用
在这里插入图片描述
提示版本不匹配

无法安装程序包“Autoupdater.NET.Official 1.9.2”。你正在尝试将此程序包安装到目标为“.NETFramework,Version=v4.5”的项目中,但该程序包不包含任何与该框架兼容的程序集引用或内容文件。有关详细信息,请联系程序包作者。

在这里插入图片描述查看介绍发现最少支持.net 4.6.2
在这里插入图片描述
往前翻一翻历史版本,发现1.8.6支持.net 4.5,再次点击安装
在这里插入图片描述点击应用
在这里插入图片描述
看到已完成说明安装完成
在这里插入图片描述

2. 准备服务器上的更新配置文件

在服务器上放置一个 update.xml 文件,内容如下(可根据需要调整字段):

<?xml version="1.0" encoding="UTF-8"?>
<item>
    <version>1.0.6.0</version>               <!-- 新版本号 -->
    <url>https://your-server.com/download/MyApp_1.0.6.0.exe</url> <!-- 新版本安装包下载地址 -->
    <mandatory>true</mandatory>             <!-- 是否为强制更新 -->
    <mandatoryVersion>1.0.3.0</mandatoryVersion> <!-- 低于此版本号将被强制更新 -->
</item>
  • version:最新版本号,主程序会用 InstalledVersion 与之比较。
  • url:新版本安装程序的下载地址,支持 HTTP/HTTPS。注意名称不能用中文,否则更新不成功。
  • mandatorytrue 表示强制更新,用户无法跳过或关闭更新窗口;false 则用户可以自行选择。(实测true也可以关闭更新)
  • mandatoryVersion:若当前程序版本低于此值,即使 mandatoryfalse,也会变为强制更新,确保旧版本用户及时升级。

将这个文件上传到你的网站服务器(如 https://your-server.com/update.xml),确保程序可以访问。可以直接在浏览器测试,能看到xml内容才算成功。
在这里插入图片描述

3. 在程序中初始化 AutoUpdater

MainForm 的构造函数中,执行以下初始化代码:

using AutoUpdaterDotNET;  // 引入命名空间
using System;              // Version 类

public MainForm()
{
    InitializeComponent();

    #region 自动更新配置初始化(AutoUpdater.NET)
    
    // 订阅 AutoUpdater 事件,以便手动检查时获得“无更新”提示
    SubscribeAutoUpdaterEvent();

    // 基础设置
    // 设置更新对话框的标题
    AutoUpdater.AppTitle = "我的应用";

    // 添加 User-Agent,部分服务器需要验证
    AutoUpdater.HttpUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";

    // AutoUpdater.NET 默认比较AssemblyVersion的版本号,但我们使用自定义的 BuildVersion.Version,
    // 因此需要手动设置已安装版本号,确保更新检查正确比较版本。
    // 配置版本号(AutoUpdater.NET 需要一个 Version 对象来比较版本,确保格式正确)
    try
    {
        Version currentVersion = new Version(BuildVersion.Version);
        AutoUpdater.InstalledVersion = currentVersion;
    }
    catch (Exception ex)
    {
        Debug.WriteLine($"版本号解析失败:{ex.Message}");
        // 可回退到程序集版本
        // AutoUpdater.InstalledVersion = Assembly.GetExecutingAssembly().GetName().Version;
    }

    // 根据编译模式设置错误报告:Debug 模式下显示详细错误,Release 关闭
#if DEBUG
    AutoUpdater.ReportErrors = true;                // 调试时显示详细错误,便于定位问题
#else
    AutoUpdater.ReportErrors = false;               // 正式版关闭错误报告,避免暴露底层细节
#endif


    // 启动更新检查(异步,不会阻塞 UI 线程)
    AutoUpdater.Start("https://your-server.com/update.xml");
    
    // 自动更新检查定时器(每隔一小时)
    InitHourlyUpdateTimer();
    
    #endregion
}

上述代码完成了最基本的配置,现在每次启动程序时都会自动检查一次更新。

中间尝试实现强制更新,但是测试了许多配置都不成功

// 强制更新,经测试均无效
/*
AutoUpdater.Mandatory = false;
AutoUpdater.UpdateMode = Mode.ForcedDownload;
*/
/*
// 强制更新时隐藏“跳过”按钮
AutoUpdater.ShowSkipButton = false;
// 强制更新时隐藏“稍后提醒”按钮
AutoUpdater.ShowRemindLaterButton = false;
// 用户点击“跳过”后,1天后提醒(默认2天)
AutoUpdater.RemindLaterAt = 1;
// 单位:天
AutoUpdater.RemindLaterTimeSpan = RemindLaterFormat.Days;
*/

4. 添加定时检查更新(如每小时一次)

启动时检查一次还不够,我们需要在程序运行期间定期检查。利用 System.Windows.Forms.Timer,设置间隔为 1 小时:

#region 自动更新检查定时器(每隔一小时)

// 更新时间间隔(毫秒),默认 1 小时 = 3600000 毫秒
private const int UpdateCheckIntervalMs = 60 * 60 * 1000;

private System.Windows.Forms.Timer hourlyUpdateTimer;

/// <summary>
/// 初始化每小时更新检查定时器
/// </summary>
private void InitHourlyUpdateTimer()
{
    hourlyUpdateTimer = new System.Windows.Forms.Timer();
    hourlyUpdateTimer.Interval = UpdateCheckIntervalMs;
    hourlyUpdateTimer.Tick += HourlyUpdateTimer_Tick;
    hourlyUpdateTimer.Start();
}

private void HourlyUpdateTimer_Tick(object sender, EventArgs e)
{
    // 定时器 Tick 时,先停止,避免重入
    hourlyUpdateTimer.Stop();
    try
    {
        // 确保自动检查时不会无端弹出“无更新”提示
        _isManualCheck = false;

        // 执行更新检查(AutoUpdater 内部会避免重复)
        AutoUpdater.Start();
    }
    finally
    {
        // 重新启动定时器,开始下一个周期
        hourlyUpdateTimer.Start();
    }
}

#endregion

在构造函数中调用 InitHourlyUpdateTimer(); 即可,前面代码已添加。

5. 添加手动检查更新按钮,并优化无更新时的提示

用户有时想主动检查是否有新版本。在“关于”页面放一个按钮,并实现手动检查。
已经时最新版本时,AutoUpdater.NET默认无提示无返回,手动检查的时候最好给用户一个提示窗口。

#region 自动更新相关(手动/自动检查区分)

/// <summary>
/// 标识当前触发的更新检查是否为手动操作(用户点击“检查更新”按钮)。
/// true:手动检查;false:自动检查(定时器触发)。
/// 用于在 CheckForUpdateEvent 事件中决定是否弹出“无可用更新”提示。
/// </summary>
private bool _isManualCheck = false;

/// <summary>
/// 订阅 AutoUpdater 的更新检查完成事件,以便自定义无更新时的提示行为。
/// 注意:订阅该事件后,AutoUpdater 将不再自动显示内置的更新对话框,
/// 需要在事件中自行处理有更新时的 UI(可复用 AutoUpdater 的默认窗体)。
/// 本实现中,仅对“无更新”情况进行处理;有更新时仍让 AutoUpdater 自动处理(需取消事件订阅或手动调用 UpdateForm)。
/// 为简化,实际采用更稳健的方法:不订阅事件,而是手动调用 Start() 后通过额外逻辑判断,
/// 但这里按用户需求给出使用事件并区分手动/自动的示例。
/// </summary>
private void SubscribeAutoUpdaterEvent()
{
    AutoUpdater.CheckForUpdateEvent += AutoUpdater_CheckForUpdateEvent;
}

/// <summary>
/// AutoUpdater 检查完成后的回调事件。
/// </summary>
/// <param name="args">包含更新信息或错误的对象</param>
private void AutoUpdater_CheckForUpdateEvent(UpdateInfoEventArgs args)
{
    // 发生错误(网络、解析等)时,无论手动/自动都提示用户(可选,根据需求调整)
    if (args.Error != null)
    {
        // 可根据 _isManualCheck 决定是否提示,此处建议始终提示便于排查
        MessageBox.Show($"检查更新失败:{args.Error.Message}", "更新错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
        _isManualCheck = false; // 重置标志
        return;
    }

    // 有可用更新时,此处可按需求显示自定义界面,或调用 AutoUpdater 的默认更新窗体
    if (args.IsUpdateAvailable)
    {
        // 使用内置更新窗体(需传入 args)
         AutoUpdater.ShowUpdateForm(args);
        return;
    }

    // 无可用更新:仅当手动检查时才提示
    if (_isManualCheck)
    {
        MessageBox.Show("当前已经是最新版本!", "检查更新", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }

    // 重置手动检查标志,防止影响下一次自动检查
    _isManualCheck = false;
}

#endregion

/// <summary>
/// 检查更新按钮点击事件:手动触发自动更新检查
/// </summary>
private void btnCheckUpdate_Click(object sender, EventArgs e)
{
    // 标记为手动检查,以便在事件中区分
    _isManualCheck = true;
    // 另一种区分方法:在手动检查前,单独访问更新路径获取最新版本,对比当前版本后再决定是否更新

    // 调用 AutoUpdater.Start() 进行更新检查(内部已有防重入机制,不会重复启动多个更新对话框)
    AutoUpdater.Start();
}

别忘了在构造函数中调用 SubscribeAutoUpdaterEvent(); 订阅事件,前面代码已添加。

通过区分手动/自动标志,我们可以让自动定时检查时“无更新”保持安静,只在用户主动点击时才弹出提示,避免打扰。

6. 完整代码片段整合

将上述代码组合到 MainForm 中,项目结构更加清晰。关键点:初始化时设置版本、启动检查和定时器,按钮事件切换标志,事件处理中区分情况。

四、测试验证

  1. 发布一个新版本:前面的版本自增教程保证了发布的新版本号会自动增加。

  2. 后台更新流程:上传新安装包到服务器,更新 XML,在旧版程序上手动点击更新,弹出更新窗口。

在这里插入图片描述

五、注意事项

  • XML 文件编码:建议使用 UTF-8 无 BOM,避免中文字符导致解析错误。虽然示例中都是英文,但良好的编码习惯很重要。
  • 下载地址:确保安装包 URL 可访问,且新安装程序能够静默覆盖旧版本(Inno Setup 生成的安装包支持静默安装参数 /VERYSILENT,但需要脚本配合,本文未深入)。
  • 版本格式AutoUpdater.InstalledVersion 必须是 System.Version 对象,构建时注意格式为 major.minor.build.revision,不能有多余的字符。
  • UAC 权限:如果程序安装在 Program Files 目录,自动更新替换文件可能需要管理员权限。大多数情况下,Inno Setup 制作的安装程序在安装时会请求管理员权限,因此更新过程可以顺利完成。
  • 更新文件替换机制:AutoUpdater.NET 并非直接覆盖正在运行的 EXE,而是利用 Windows 的“重启后替换”机制或临时文件,具体可查阅其文档。一般来说,它会将新文件下载到临时目录,然后启动新安装包,由安装包完成后续工作。
  • 网络请求超时:如果服务器响应很慢,AutoUpdater 可能长时间无响应,可根据需要调整 HttpUserAgent 和超时设置(高版本 AutoUpdater 可能不支持直接设置超时,此时可自行继承或使用异步方式包装,但本教程不做深入)。
  • 调试模式:Debug 时 ReportErrors = true,会弹出详细错误信息,方便排查;Release 时务必设为 false,防止暴露内部路径等敏感信息给用户。

六、总结

通过本篇,我们为 WinForms 程序集成了 AutoUpdater.NET 自动更新组件,实现了:

  • 程序启动时自动检查更新
  • 每小时后台轮询更新
  • 用户手动检查更新
  • 无更新时静默,手动检查才提示

配合之前文章中的版本自增、开机自启、托盘运行,一个成熟稳定的桌面应用程序框架已经搭建完成。你现在可以将自己的业务逻辑填入其中,专注于核心功能的开发,而不用担心分发和更新的问题。


后记

文中代码均已在实际项目中稳定运行,NuGet 包版本为 1.8.6,其他版本可能略有差异,请参考官方文档。如有任何疑问,欢迎在评论区留言交流。


参考文献

AutoUpdater.NET
如何为你的 .NET 应用程序添加自动更新功能?
AutoUpdater.NET:5步实现.NET桌面应用自动更新终极指南
轻松实现.NET应用自动更新:AutoUpdater.NET教程


喜欢的点个关注吧><!祝你永无bug~

/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            佛祖保佑       永无BUG
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荔枝吻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值