基于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替换方案

相关推荐
小满Autumn32 分钟前
log4net 日志框架 — 从配置到实战速查手册
笔记·c#·.net·wpf·上位机·log4net
yaoxin5211234 小时前
434. Java 日期时间 API - Period 基于日期的时间段
java·开发语言·python
凡人叶枫4 小时前
Effective C++ 条款30:透彻了解 inlining 的里里外外
linux·开发语言·c++·嵌入式开发·effective c++
学逆向的5 小时前
C++纯虚函数
开发语言·c++·网络安全
程序员二叉5 小时前
【JUC】ThreadLocal底层原理|内存泄漏|弱引用|跨线程传递方案
java·开发语言·面试·职场和发展·juc
程序员二叉5 小时前
【JUC】线程池全套深度详解|参数|流程|拒绝策略|调优|异常处理
java·开发语言·jvm·算法·面试·juc
JaydenAI5 小时前
[对比学习LangChain和MAF-07]如何引入人机交互的审批流程
python·ai·langchain·c#·agent·hitl·maf
凡人叶枫6 小时前
Effective C++ 条款22:将成员变量声明为 private
linux·开发语言·c++
Qt程序员6 小时前
掌握 Linux 内核调度:从原理到实现(进程篇)
java·开发语言
code bean6 小时前
【LangChain】检索器完全指南:从向量检索到生产级 RAG 架构
java·开发语言·微服务