【手把手实战教学】基于C#和.NET Framework的WinForms开发教程系列(6)AutoUpdater.NET 自动更新
系列目录
(1)Visual Studio 2026 中创建、运行、发布应用
(2)开机自启
(3)自动定时更新
(4)后台运行
(5)版本自增
(6)AutoUpdater.NET 自动更新
文章目录
- 【手把手实战教学】基于C#和.NET Framework的WinForms开发教程系列(6)AutoUpdater.NET 自动更新
- 前言
- 一、为什么需要自动更新?
- 二、实现原理
- 三、实现步骤
- 1. 安装 NuGet 包
- 2. 准备服务器上的更新配置文件
- 3. 在程序中初始化 AutoUpdater
- 4. 添加定时检查更新(如每小时一次)
- 5. 添加手动检查更新按钮,并优化无更新时的提示
- 6. 完整代码片段整合
- 四、测试验证
- 五、注意事项
- 六、总结
- 后记
- 参考文献
前言
开发环境:
IDE:Visual Studio 2026
语言:C#
框架:.NET Framework 4.5
UI:WinForms
在前面的文章中,我们让程序拥有了开机自启、定时任务、后台托盘等强大能力,并且通过自动生成脚本实现了版本号递增。但是,如果新版本只停留在开发者的电脑上,用户永远不会知道。如何让用户手中的软件自动检测并升级到最新版本,是商业软件必须要解决的问题。
本文将使用开源库AutoUpdater.NET,仅需几十行代码,就能为你的 WinForms 程序添加强大的自动更新功能。
我们将从 NuGet 包的安装、服务器更新配置文件的准备,到程序中定时/手动检查更新的实现,一步步带你完成。
一、为什么需要自动更新?
传统的软件更新方式通常需要用户主动访问官网、下载安装包、卸载旧版本再安装新版本。这个过程不仅繁琐,而且用户往往因为嫌麻烦而停留在旧版本,导致 Bug 得不到修复、新功能无法触达,甚至引发兼容性问题。
有了自动更新后,程序可以在后台静默检查新版本,当发现更新时弹出友好的升级提示窗口,用户只需点击一下“更新”,程序就会自动下载并替换为新版本,整个过程无需离开软件界面,极大提升了用户体验和版本覆盖率。
二、实现原理
AutoUpdater.NET 是一个专门为 .NET WinForms / WPF 设计的自动更新组件,它的工作流程如下:
- 程序启动或定时触发时,向指定的 URL 请求一个
update.xml文件。 - 解析 XML 中的最新版本号、下载地址、更新日志、是否强制更新等信息。
- 与当前程序版本(通过
InstalledVersion属性设定)进行比较。 - 如果有新版本,弹出更新对话框,用户可以选择立即更新、稍后提醒或跳过;如果设置为强制更新,则用户不能跳过或关闭。
- 下载完成后,自动替换当前运行的程序文件(利用系统的文件移动特性),完成更新。
整个流程只需我们准备一个简单的 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。注意名称不能用中文,否则更新不成功。mandatory:true表示强制更新,用户无法跳过或关闭更新窗口;false则用户可以自行选择。(实测true也可以关闭更新)mandatoryVersion:若当前程序版本低于此值,即使mandatory为false,也会变为强制更新,确保旧版本用户及时升级。
将这个文件上传到你的网站服务器(如https://your-server.com/update.xml),确保程序可以访问。可以直接在浏览器测试,能看到xml内容才算成功。
3. 在程序中初始化 AutoUpdater
在MainForm的构造函数中,执行以下初始化代码:
usingAutoUpdaterDotNET;// 引入命名空间usingSystem;// Version 类publicMainForm(){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{VersioncurrentVersion=newVersion(BuildVersion.Version);AutoUpdater.InstalledVersion=currentVersion;}catch(Exceptionex){Debug.WriteLine($"版本号解析失败:{ex.Message}");// 可回退到程序集版本// AutoUpdater.InstalledVersion = Assembly.GetExecutingAssembly().GetName().Version;}// 根据编译模式设置错误报告:Debug 模式下显示详细错误,Release 关闭#ifDEBUGAutoUpdater.ReportErrors=true;// 调试时显示详细错误,便于定位问题#elseAutoUpdater.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 毫秒privateconstintUpdateCheckIntervalMs=60*60*1000;privateSystem.Windows.Forms.TimerhourlyUpdateTimer;/// <summary>/// 初始化每小时更新检查定时器/// </summary>privatevoidInitHourlyUpdateTimer(){hourlyUpdateTimer=newSystem.Windows.Forms.Timer();hourlyUpdateTimer.Interval=UpdateCheckIntervalMs;hourlyUpdateTimer.Tick+=HourlyUpdateTimer_Tick;hourlyUpdateTimer.Start();}privatevoidHourlyUpdateTimer_Tick(objectsender,EventArgse){// 定时器 Tick 时,先停止,避免重入hourlyUpdateTimer.Stop();try{// 确保自动检查时不会无端弹出“无更新”提示_isManualCheck=false;// 执行更新检查(AutoUpdater 内部会避免重复)AutoUpdater.Start();}finally{// 重新启动定时器,开始下一个周期hourlyUpdateTimer.Start();}}#endregion在构造函数中调用InitHourlyUpdateTimer();即可,前面代码已添加。
5. 添加手动检查更新按钮,并优化无更新时的提示
用户有时想主动检查是否有新版本。在“关于”页面放一个按钮,并实现手动检查。
已经时最新版本时,AutoUpdater.NET默认无提示无返回,手动检查的时候最好给用户一个提示窗口。
#region自动更新相关(手动/自动检查区分)/// <summary>/// 标识当前触发的更新检查是否为手动操作(用户点击“检查更新”按钮)。/// true:手动检查;false:自动检查(定时器触发)。/// 用于在 CheckForUpdateEvent 事件中决定是否弹出“无可用更新”提示。/// </summary>privatebool_isManualCheck=false;/// <summary>/// 订阅 AutoUpdater 的更新检查完成事件,以便自定义无更新时的提示行为。/// 注意:订阅该事件后,AutoUpdater 将不再自动显示内置的更新对话框,/// 需要在事件中自行处理有更新时的 UI(可复用 AutoUpdater 的默认窗体)。/// 本实现中,仅对“无更新”情况进行处理;有更新时仍让 AutoUpdater 自动处理(需取消事件订阅或手动调用 UpdateForm)。/// 为简化,实际采用更稳健的方法:不订阅事件,而是手动调用 Start() 后通过额外逻辑判断,/// 但这里按用户需求给出使用事件并区分手动/自动的示例。/// </summary>privatevoidSubscribeAutoUpdaterEvent(){AutoUpdater.CheckForUpdateEvent+=AutoUpdater_CheckForUpdateEvent;}/// <summary>/// AutoUpdater 检查完成后的回调事件。/// </summary>/// <param name="args">包含更新信息或错误的对象</param>privatevoidAutoUpdater_CheckForUpdateEvent(UpdateInfoEventArgsargs){// 发生错误(网络、解析等)时,无论手动/自动都提示用户(可选,根据需求调整)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>privatevoidbtnCheckUpdate_Click(objectsender,EventArgse){// 标记为手动检查,以便在事件中区分_isManualCheck=true;// 另一种区分方法:在手动检查前,单独访问更新路径获取最新版本,对比当前版本后再决定是否更新// 调用 AutoUpdater.Start() 进行更新检查(内部已有防重入机制,不会重复启动多个更新对话框)AutoUpdater.Start();}别忘了在构造函数中调用SubscribeAutoUpdaterEvent();订阅事件,前面代码已添加。
通过区分手动/自动标志,我们可以让自动定时检查时“无更新”保持安静,只在用户主动点击时才弹出提示,避免打扰。
6. 完整代码片段整合
将上述代码组合到MainForm中,项目结构更加清晰。关键点:初始化时设置版本、启动检查和定时器,按钮事件切换标志,事件处理中区分情况。
四、测试验证
发布一个新版本:前面的版本自增教程保证了发布的新版本号会自动增加。
后台更新流程:上传新安装包到服务器,更新 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 */