前言
在实际开发中,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>
publicclassUpdateEntity
{
    /// <summary>
    /// 提供更新的版本号
    /// </summary>
    publicstring latestversion { get; set; }
    /// <summary>
    /// 更新包的下载路径, 这里将需要更新的文件压缩成zip文件
    /// </summary>
    publicstring downloadurl { get; set; }
    /// <summary>
    /// 更新日志
    /// </summary>
    publicstring changelog { get; set; }
    /// <summary>
    /// 是否是强制更新
    /// </summary>
    publicbool mandatory { get; set; }
}
3、窗体界面截图(进度条展示更新状态)
 4、完整核心代码
4、完整核心代码以下为完整的 WinForm 自动更新窗体逻辑代码:
using ICSharpCode.SharpZipLib.Zip;
using Newtonsoft.Json;
using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Windows.Forms;
namespaceOnlineUpdateDemo
{
    publicpartialclassForm1 : Form
    {
        privatestring NowVersion;
        privatestring InstallPath;
        privatestring 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
阅读原文:原文链接
该文章在 2025/7/29 22:45:27 编辑过