WinForm 实现自动更新功能详解

423 阅读4分钟

前言

在实际开发中,WinForm 应用程序的版本管理是一个常见需求。传统的发布方式如 ClickOnce 虽然方便,但在某些场景下会出现 DLL 文件缺失、更新失败等问题。

本文介绍一种基于代码实现的在线自动更新机制,通过读取服务器上的版本信息与本地对比,判断是否需要下载并更新程序。

该方案使用 JSON 配置文件进行版本控制,结合 ZIP 压缩包实现更新逻辑,并利用 FastZip 进行解压操作,适用于中小型项目快速集成自动更新功能。

实现思路

1、在 IIS 或 Web 服务器上部署更新包(ZIP 格式)和版本信息文件(JSON 格式)。

2、客户端启动时读取本地版本号,并向服务器请求最新的版本信息。

3、比对版本号,若服务器版本高于本地,则触发更新流程。

4、下载 ZIP 更新包后进行解压替换原有文件。

5、重启主程序完成更新。

这种方式避免了传统 ClickOnce 的兼容性问题,具有更高的灵活性和可控性。

系统结构说明

1、版本配置文件(updates.json)

{
  "latestversion": "3.0.3",
  "downloadurl": "http://127.0.0.1:8091/FD3_WcsClient.zip",
  "changelog": "更改日志",
  "mandatory": true
}

2、对应实体类 UpdateEntity

/// <summary>
/// 更新信息
/// </summary>
public class UpdateEntity
{
    /// <summary>
    /// 提供更新的版本号
    /// </summary>
    public string latestversion { get; set; }

    /// <summary>
    /// 更新包的下载路径, 这里将需要更新的文件压缩成zip文件
    /// </summary>
    public string downloadurl { get; set; }

    /// <summary>
    /// 更新日志
    /// </summary>
    public string changelog { get; set; }

    /// <summary>
    /// 是否是强制更新
    /// </summary>
    public bool mandatory { get; set; }
}

3、窗体界面截图(进度条展示更新状态)

4、完整核心代码

以下为完整的 WinForm 自动更新窗体逻辑代码:

using ICSharpCode.SharpZipLib.Zip;
using Newtonsoft.Json;
using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Windows.Forms;

namespace OnlineUpdateDemo
{
    public partial class Form1 : Form
    {
        private string NowVersion;
        private string InstallPath;
        private string StartPath;
        private UpdateEntity updateEntity = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 获取当前版本号
            NowVersion = ConfigurationManager.AppSettings["Version"];
            // 获取解压目录
            InstallPath = ConfigurationManager.AppSettings["InstallPath"];
            // 获取启动路径
            StartPath = ConfigurationManager.AppSettings["StartPath"];

            // 获取更新配置
            string UpdateEntityUrl = ConfigurationManager.AppSettings["UpdateEntityUrl"];
            string updateJson = GetHtml(UpdateEntityUrl);
            updateEntity = JsonConvert.DeserializeObject<UpdateEntity>(updateJson);

            // 显示版本信息
            this.label_NowVersion.Text = NowVersion;
            this.label_NextVersion.Text = updateEntity.latestversion;

            if (string.Compare(updateEntity.latestversion, NowVersion) > 0)
            {
                label_message.Text = "有新版本";

                if (updateEntity.mandatory)
                {
                    Btn_Next_Click(null, null);
                }
            }
            else
            {
                label_message.Text = "没有更新版本了";
                if (updateEntity.mandatory)
                {
                    ShowLogin(); // 启动主程序
                }
            }
        }

        private void Btn_Next_Click(object sender, EventArgs e)
        {
            try
            {
                WebClient wc = new WebClient();
                wc.DownloadProgressChanged += Wc_DownloadProgressChanged;
                Uri uri = new Uri(updateEntity.downloadurl);

                if (!Directory.Exists(InstallPath))
                {
                    Directory.CreateDirectory(InstallPath);
                }

                wc.DownloadFileAsync(uri, InstallPath + "FD3_WcsClient.zip");
            }
            catch (Exception er)
            {
                MessageBox.Show("下载失败:" + er.Message);
            }
        }

        private void Btn_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
            this.Dispose();
        }

        private void Btn_Login_Click(object sender, EventArgs e)
        {
            ShowLogin();
        }

        private void Wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            Action act = () =>
            {
                this.progressBar1.Value = e.ProgressPercentage;
                label_message.Text = "正在下载.....";
            };
            this.Invoke(act);

            if (e.ProgressPercentage == 100)
            {
                label_message.Text = "正在解压.....";

                try
                {
                    string zipFileName = InstallPath + "FD3_WcsClient.zip";
                    string targetDirectory = InstallPath;

                    var result = Compress(targetDirectory, zipFileName, "");
                    if (result == "Success!")
                    {
                        progressBar1.Value = 100;
                        this.label_message.Text = "更新完成";

                        // 更新配置文件中的版本号
                        Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                        config.AppSettings.Settings["Version"].Value = updateEntity.latestversion;
                        config.Save(ConfigurationSaveMode.Full);
                        ConfigurationManager.RefreshSection("appSettings");

                        ShowLogin(); // 启动主程序
                    }
                    else
                    {
                        MessageBox.Show("更新失败:" + result);
                        this.Close();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("解压失败:" + ex.Message);
                }
            }
        }

        public string GetHtml(string url)
        {
            try
            {
                using (WebClient client = new WebClient())
                {
                    byte[] data = client.DownloadData(url);
                    using (var ms = new MemoryStream(data))
                    using (var sr = new StreamReader(ms, Encoding.UTF8))
                    {
                        return sr.ReadToEnd();
                    }
                }
            }
            catch (Exception)
            {
                MessageBox.Show("网络连接失败");
                return "";
            }
        }

        public string Compress(string DirPath, string ZipPath, string ZipPWD)
        {
            string state = "Fail!";
            if (!Directory.Exists(DirPath) || !File.Exists(ZipPath)) return state;

            try
            {
                FastZip fastZip = new FastZip();
                fastZip.ExtractZip(ZipPath, DirPath, ZipPWD);
                state = "Success!";
            }
            catch (Exception ex)
            {
                state += ", " + ex.Message;
            }

            return state;
        }

        public void ShowLogin()
        {
            System.Diagnostics.Process.Start(StartPath);
            GC.Collect();
            Application.Exit();
        }
    }
}

5、配置文件 App.config 内容

<configuration>
  <appSettings>
    <!-- 当前版本号 -->
    <add key="Version" value="3.0.2" />
    <!-- 版本配置文件地址 -->
    <add key="UpdateEntityUrl" value="http://192.168.31.2:8091/updates.json" />
    <!-- 解压目录 -->
    <add key="InstallPath" value="D:/WCS_Project/" />
    <!-- 主程序启动路径 -->
    <add key="StartPath" value="D:/WCS_Project/福鼎物流控制系统.exe" />
  </appSettings>
</configuration>

总结

本文详细介绍了如何使用 C# 编写一个 WinForm 自动更新程序。通过比对远程 JSON 中的版本号,决定是否下载并解压 ZIP 包进行更新。整个过程无需依赖 ClickOnce,更加灵活可靠,适合需要自定义更新策略的项目。

方案可扩展性强,未来可加入差分更新、断点续传、数字签名验证等高级功能,进一步提升系统的稳定性和安全性。

关键词

WinForm、自动更新、C#、在线升级、版本控制、ZIP解压、JSON配置、IIS部署、ICSharpCode.SharpZipLib、FastZip

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

优秀是一种习惯,欢迎大家留言学习!

作者:搬砖工具人

出处:cnblogs.com/wangshunyun/p/16463258.html

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!