基于C# WinForm实现自动在线升级的方案

一、系统架构设计

HTTPS
有新版本
无更新
客户端
更新服务器
版本检测接口
更新包下载
版本比较
生成差异包
结束
分块加密传输
本地校验
静默安装
进程重启


二、核心代码实现

1. 版本检测模块(VersionChecker.cs)
csharp 复制代码
public class VersionInfo
{
    public string CurrentVersion { get; set; }
    public string LatestVersion { get; set; }
    public string UpdateUrl { get; set; }
    public long FileSize { get; set; }
    public string Checksum { get; set; }
}

public async Task<VersionInfo> CheckUpdateAsync()
{
    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("User-Agent", "WinUpdater/1.0");
    
    // 获取版本信息
    var versionResp = await client.GetAsync("https://update.example.com/api/version");
    var versionData = JsonConvert.DeserializeObject<VersionInfo>(await versionResp.Content.ReadAsStringAsync());
    
    // 比较版本
    if (new Version(versionData.LatestVersion) > new Version(Assembly.GetExecutingAssembly().GetName().Version))
    {
        versionData.UpdateUrl = $"https://update.example.com/update_{versionData.LatestVersion}.zip";
        return versionData;
    }
    return null;
}
2. 差分更新模块(DiffUpdate.cs)
csharp 复制代码
public class DiffUpdate
{
    private readonly string _localDir = Path.Combine(Application.StartupPath, "temp");
    private readonly string _updateFile = "update.zip";
    
    public async Task DownloadUpdateAsync(string url)
    {
        using var client = new HttpClient();
        client.DownloadProgressChanged += (s, e) => UpdateProgress(e.ProgressPercentage);
        
        var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
        response.EnsureSuccessStatusCode();
        
        using var stream = await response.Content.ReadAsStreamAsync();
        using var fileStream = new FileStream(Path.Combine(_localDir, _updateFile), FileMode.Create);
        await stream.CopyToAsync(fileStream);
    }

    private void UpdateProgress(int percentage)
    {
        if (InvokeRequired)
        {
            Invoke(new Action(() => UpdateProgress(percentage)));
            return;
        }
        
        progressBar.Value = percentage;
        lblStatus.Text = $"{percentage}% ({new FileInfo(Path.Combine(_localDir, _updateFile)).Length / 1024} KB)";
    }
}
3. 文件校验与替换(FileHandler.cs)
csharp 复制代码
public class FileHandler
{
    public bool VerifyChecksum(string filePath, string expectedHash)
    {
        using var sha256 = SHA256.Create();
        using var stream = File.OpenRead(filePath);
        var hash = BitConverter.ToString(sha256.ComputeHash(stream)).Replace("-", "").ToLower();
        return hash == expectedHash;
    }

    public void ApplyUpdate(string zipPath, string backupDir)
    {
        if (!Directory.Exists(backupDir)) Directory.CreateDirectory(backupDir);
        
        // 备份旧文件
        var files = Directory.GetFiles(Application.StartupPath, "*.*", SearchOption.AllDirectories);
        foreach (var file in files)
        {
            var relativePath = file.Substring(Application.StartupPath.Length + 1);
            var backupPath = Path.Combine(backupDir, relativePath);
            Directory.CreateDirectory(Path.GetDirectoryName(backupPath));
            File.Copy(file, backupPath, true);
        }

        // 解压更新包
        ZipFile.ExtractToDirectory(zipPath, Application.StartupPath, overwrite: true);
        
        // 清理临时文件
        Directory.Delete(backupDir, true);
        File.Delete(zipPath);
    }
}

三、用户界面设计(WinForm)

1. 主界面布局(MainForm.Designer.cs)
csharp 复制代码
partial class MainForm
{
    private System.ComponentModel.IContainer components = null;
    private ProgressBar progressBar;
    private Label lblStatus;
    private Button btnCheckUpdate;

    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    private void InitializeComponent()
    {
        this.btnCheckUpdate = new System.Windows.Forms.Button();
        this.progressBar = new System.Windows.Forms.ProgressBar();
        this.lblStatus = new System.Windows.Forms.Label();
        
        this.btnCheckUpdate.Location = new System.Drawing.Point(20, 20);
        this.btnCheckUpdate.Size = new System.Drawing.Size(120, 30);
        this.btnCheckUpdate.Text = "检查更新";
        this.btnCheckUpdate.Click += new System.EventHandler(this.btnCheckUpdate_Click);
        
        this.progressBar.Location = new System.Drawing.Point(20, 60);
        this.progressBar.Size = new System.Drawing.Size(400, 23);
        
        this.lblStatus.Location = new System.Drawing.Point(20, 90);
        this.lblStatus.AutoSize = true;
        
        this.ClientSize = new System.Drawing.Size(450, 150);
        this.Controls.Add(this.lblStatus);
        this.Controls.Add(this.progressBar);
        this.Controls.Add(this.btnCheckUpdate);
        this.Name = "MainForm";
        this.Text = "自动更新客户端";
    }
}

四、关键功能实现

1. 静默安装与进程重启
csharp 复制代码
public void PerformSilentInstall()
{
    // 生成批处理脚本
    var batPath = Path.Combine(Application.StartupPath, "update.bat");
    File.WriteAllText(batPath, $@"
        @echo off
        taskkill /f /im {Assembly.GetExecutingAssembly().GetName().Name}.exe
        timeout /t 2
        start "" "" {Path.Combine(Application.StartupPath, "update.exe")}
        exit
    ");
    
    // 执行更新
    Process.Start(batPath);
    Application.Exit();
}
2. 断点续传实现
csharp 复制代码
public async Task ResumeDownload(string url, string localPath)
{
    using var client = new HttpClient();
    var rangeHeader = new RangeHeaderValue(File.Exists(localPath) 
        ? new FileInfo(localPath).Length 
        : 0, null);
    
    client.DefaultRequestHeaders.Range.Add(rangeHeader);
    
    using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
    using var fileStream = new FileStream(localPath, FileMode.Append);
    await response.Content.CopyToAsync(fileStream);
}

五、服务器端配置

1. 更新信息接口(ASP.NET Core)
csharp 复制代码
[ApiController]
[Route("api/[controller]")]
public class UpdateController : ControllerBase
{
    [HttpGet("version")]
    public IActionResult GetVersion()
    {
        var version = new {
            current = "1.0.0",
            latest = "1.0.1",
            url = "https://update.example.com/updates/1.0.1.zip",
            checksum = "a1b2c3d4e5f6..."
        };
        return Ok(version);
    }
}
2. 更新包构建工具
csharp 复制代码
public class UpdateBuilder
{
    public void CreateUpdatePackage(string sourceDir, string outputPath)
    {
        using var zip = new ZipArchive(File.Create(outputPath), ZipArchiveMode.Create);
        
        foreach (var file in Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories))
        {
            var entry = zip.CreateEntry(Path.GetRelativePath(sourceDir, file));
            using var entryStream = entry.Open();
            File.Copy(file, entryStream.Name, true);
        }
    }
}

六、安全增强方案

1. 数字签名验证
csharp 复制代码
public bool VerifySignature(string filePath)
{
    var signer = new SignedCms();
    signer.Decode(File.ReadAllBytes(filePath));
    signer.VerifySignature(false);
    return true;
}
2. 回滚机制
csharp 复制代码
public void RollbackUpdate(string backupDir)
{
    var backupFiles = Directory.GetFiles(backupDir, "*.*", SearchOption.AllDirectories);
    foreach (var file in backupFiles)
    {
        var relativePath = file.Substring(backupDir.Length + 1);
        var targetPath = Path.Combine(Application.StartupPath, relativePath);
        Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
        File.Copy(file, targetPath, true);
    }
}

七、部署与测试

1. 安装包配置(MSI)
csharp 复制代码
<!-- WiX安装配置 -->
<Product Id="*" Name="AutoUpdater" Language="1033" Version="1.0.0">
  <Directory Id="TARGETDIR" Name="SourceDir">
    <Directory Id="ProgramFilesFolder">
      <Directory Id="INSTALLDIR" Name="AutoUpdater">
        <Component Id="MainComponent">
          <File Id="UpdateExe" Source="AutoUpdater.exe"/>
          <File Id="UpdateDll" Source="UpdateLib.dll"/>
        </Component>
      </Directory>
    </Directory>
  </Directory>
</Product>
2. 压力测试方案
csharp 复制代码
// 模拟1000用户并发更新
var tasks = new List<Task>();
for (int i = 0; i < 1000; i++)
{
    tasks.Add(Task.Run(async () => 
    {
        var client = new HttpClient();
        await client.GetAsync("https://update.example.com/update.zip");
    }));
}
await Task.WhenAll(tasks);

参考代码 基于C#开发的一个Winform自动在线升级程序 www.youwenfan.com/contentcsr/112231.html

八、扩展功能建议

  1. 增量更新:仅下载差异文件(bsdiff算法)

  2. 多通道支持:同时支持HTTP/HTTPS/FTP协议

  3. 灰度发布:按用户组逐步推送更新

  4. 热更新:不重启进程的DLL替换方案

相关推荐
历程里程碑1 小时前
26信号处理一:从闹钟到进程控制的奥秘
linux·运维·服务器·开发语言·c++·算法·排序算法
Gofarlic_OMS1 小时前
LS-DYNA许可证全局状态及集群计算资源使用可视化监控大屏
运维·开发语言·算法·matlab·自动化
阿里嘎多学长1 小时前
2026-02-25 GitHub 热点项目精选
开发语言·程序员·github·代码托管
troublea1 小时前
ThinkPHP vs Laravel:PHP框架终极对决
开发语言·php·laravel
Ronin3051 小时前
信道管理模块和异步线程模块
开发语言·c++·rabbitmq·异步线程·信道管理
LawrenceLan1 小时前
30.Flutter 零基础入门(三十):GridView 网格布局 —— 九宫格与商品列表必学
开发语言·前端·flutter·dart
yoyo君~2 小时前
从内存管理到并发架构:C++ 核心内功修炼指南
开发语言·c++·学习·无人机
2501_941982052 小时前
告别手动,Java 自动化调用企微外部群的深度实践
开发语言·python
大尚来也2 小时前
从调度到实时:Linux 下 DolphinScheduler 驱动 Flink 消费 Kafka 的实战指南
c#·linq