超碰人人人人人,亚洲AV午夜福利精品一区二区,亚洲欧美综合区丁香五月1区,日韩欧美亚洲系列

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

【C#】.NET 程序自動(dòng)更新組件

admin
2025年5月3日 15:21 本文熱度 75

前言

本來博主想偷懶使用AutoUpdater.NET組件,但由于博主項(xiàng)目有些特殊性和它的功能過于多,于是博主自己實(shí)現(xiàn)一個(gè)輕量級獨(dú)立自動(dòng)更新組件,可稍作修改集成到大家自己項(xiàng)目中,比如:WPF/Winform/Windows服務(wù)。

大致思路:發(fā)現(xiàn)更新后,從網(wǎng)絡(luò)上下載更新包并進(jìn)行解壓,同時(shí)在 WinForms 應(yīng)用程序中顯示下載和解壓進(jìn)度條,并重啟程序。以提供更好的用戶體驗(yàn)。

系統(tǒng)架構(gòu)概覽

自動(dòng)化軟件更新系統(tǒng)主要包括以下幾個(gè)核心部分:

  • 版本檢查:定期或在啟動(dòng)時(shí)檢查服務(wù)器上的最新版本。

  • 下載更新:如果發(fā)現(xiàn)新版本,則從服務(wù)器下載更新包。

  • 解壓縮與安裝:解壓下載的更新包,替換舊文件。

  • 重啟應(yīng)用:更新完畢后,重啟應(yīng)用以加載新版本。

組件實(shí)現(xiàn)細(xì)節(jié)

獨(dú)立更新程序邏輯

1、創(chuàng)建 WinForms 應(yīng)用程序

首先,創(chuàng)建一個(gè)新的 WinForms 應(yīng)用程序,用來承載獨(dú)立的自動(dòng)更新程序,界面就簡單兩個(gè)組件:

添加一個(gè) ProgressBar 和一個(gè) TextBox 控件,用于顯示進(jìn)度和信息提示。

2、主窗體加載事件

我們在主窗體的 Load 事件中完成以下步驟:

  • 解析命令行參數(shù)。

  • 關(guān)閉當(dāng)前運(yùn)行的程序。

  • 下載更新包并顯示下載進(jìn)度。

  • 解壓更新包并顯示解壓進(jìn)度。

  • 啟動(dòng)解壓后的新版本程序。

下面是主窗體 Form1_Load 事件處理程序的代碼:

private async void Form1_Load(object sender, EventArgs e)
{
    // 讀取和解析命令行參數(shù)
    var args = Environment.GetCommandLineArgs();
    if (!ParseArguments(args, out string downloadUrl, out string programToLaunch, out string currentProgram))
    {
        _ = MessageBox.Show("請?zhí)峁┯行У南螺d地址和啟動(dòng)程序名稱的參數(shù)。");
        Application.Exit();
        return;
    }
    // 關(guān)閉當(dāng)前運(yùn)行的程序
    Process[] processes = Process.GetProcessesByName(currentProgram);
    foreach (Process process in processes)
    {
        process.Kill();
        process.WaitForExit();
    }
    // 開始下載和解壓過程
    string downloadPath = Path.Combine(Path.GetTempPath(), Path.GetFileName(downloadUrl));

    progressBar.Value = 0;
    textBoxInformation.Text = "下載中...";

    await DownloadFileAsync(downloadUrl, downloadPath);

    progressBar.Value = 0;
    textBoxInformation.Text = "解壓中...";

    await Task.Run(() => ExtractZipFile(downloadPath, AppDomain.CurrentDomain.BaseDirectory));

    textBoxInformation.Text = "完成";

    // 啟動(dòng)解壓后的程序
    string programPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, programToLaunch);
    if (File.Exists(programPath))
    {
        _ = Process.Start(programPath);
        Application.Exit();
    }
    else
    {
        _ = MessageBox.Show($"無法找到程序:{programPath}");
    }
}

3、解析命令行參數(shù)

我們需要從命令行接收下載地址、啟動(dòng)程序名稱和當(dāng)前運(yùn)行程序的名稱。以下是解析命令行參數(shù)的代碼:

private bool ParseArguments(string[] args, out string downloadUrl, out string programToLaunch, out string currentProgram)
{
    downloadUrl = null;
    programToLaunch = null;
    currentProgram = null;

    for (int i = 1; i < args.Length; i++)
    {
        if (args[i].StartsWith("--url="))
        {
            downloadUrl = args[i].Substring("--url=".Length);
        }
        else if (args[i] == "--url" && i + 1 < args.Length)
        {
            downloadUrl = args[++i];
        }
        else if (args[i].StartsWith("--launch="))
        {
            programToLaunch = args[i].Substring("--launch=".Length);
        }
        else if (args[i] == "--launch" && i + 1 < args.Length)
        {
            programToLaunch = args[++i];
        }
        else if (args[i].StartsWith("--current="))
        {
            currentProgram = args[i].Substring("--current=".Length);
        }
        else if (args[i] == "--current" && i + 1 < args.Length)
        {
            currentProgram = args[++i];
        }
    }

    return !string.IsNullOrEmpty(downloadUrl) && !string.IsNullOrEmpty(programToLaunch) && !string.IsNullOrEmpty(currentProgram);
}

4、下載更新包并顯示進(jìn)度

使用 HttpClient 下載文件,并在下載過程中更新進(jìn)度條:

private async Task DownloadFileAsync(string url, string destinationPath)
{
    using (HttpClient client = new HttpClient())
    {
        using (HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
        {
            _ = response.EnsureSuccessStatusCode();

            long? totalBytes = response.Content.Headers.ContentLength;

            using (var stream = await response.Content.ReadAsStreamAsync())
            using (var fileStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write, FileShare.None, 8192true))
            {
                var buffer = new byte[8192];
                long totalRead = 0;
                int bytesRead;

                while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) != 0)
                {
                    await fileStream.WriteAsync(buffer, 0, bytesRead);
                    totalRead += bytesRead;

                    if (totalBytes.HasValue)
                    {
                        int progress = (int)((double)totalRead / totalBytes.Value * 100);
                        _ = Invoke(new Action(() => progressBar.Value = progress));
                    }
                }
            }
        }
    }
}

5、解壓更新包并顯示進(jìn)度

在解壓過程中跳過 Updater.exe 文件(因?yàn)楫?dāng)前更新程序正在運(yùn)行,大家可根據(jù)需求修改邏輯),并捕獲異常以確保進(jìn)度條和界面更新:

private void ExtractZipFile(string zipFilePath, string extractPath)
{
    using (ZipArchive archive = ZipFile.OpenRead(zipFilePath))
    {
        int totalEntries = archive.Entries.Count;
        int extractedEntries = 0;

        foreach (ZipArchiveEntry entry in archive.Entries)
        {
            try
            {
                // 跳過 Updater.exe 文件
                if (entry.FullName.Equals(CustConst.AppNmae, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }
                string destinationPath = Path.Combine(extractPath, entry.FullName);

                _ = Invoke(new Action(() => textBoxInformation.Text = $"解壓中... {entry.FullName}"));

                if (string.IsNullOrEmpty(entry.Name))
                {
                    // Create directory
                    _ = Directory.CreateDirectory(destinationPath);
                }
                else
                {
                    // Ensure directory exists
                    _ = Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
                    // Extract file
                    entry.ExtractToFile(destinationPath, overwrite: true);
                }

                extractedEntries++;
                int progress = (int)((double)extractedEntries / totalEntries * 100);
                _ = Invoke(new Action(() => progressBar.Value = progress));
            }
            catch (Exception ex)
            {
                _ = Invoke(new Action(() => textBoxInformation.Text = $"解壓失?。?span style="-webkit-tap-highlight-color: transparent; margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; color: rgb(224, 108, 117); line-height: 26px;">{entry.FullName}, 錯(cuò)誤: {ex.Message}"));
                continue;
            }
        }
    }
}

6、啟動(dòng)解壓后的新程序

在解壓完成后,啟動(dòng)新版本的程序,并且關(guān)閉更新程序:

private void Form1_Load(object sender, EventArgs e)
{
    // 省略部分代碼...

    string programPath = Path.Combine(extractPath, programToLaunch);
    if (File.Exists(programPath))
    {
        Process.Start(programPath);
        Application.Exit();
    }
    else
    {
        MessageBox.Show($"無法找到程序:{programPath}");
    }
}

檢查更新邏輯

1、創(chuàng)建 UpdateChecker 類

創(chuàng)建一個(gè) UpdateChecker 類,對外提供引用,用于檢查更新并啟動(dòng)更新程序:

public static class UpdateChecker
{
    public static string UpdateUrl { getset; }
    public static string CurrentVersion { getset; }
    public static string MainProgramRelativePath { getset; }

    public static void CheckForUpdates()
    {
        try
        {
            using (HttpClient client = new HttpClient())
            {
                string xmlContent = client.GetStringAsync(UpdateUrl).Result;
                XDocument xmlDoc = XDocument.Parse(xmlContent);

                var latestVersion = xmlDoc.Root.Element("version")?.Value;
                var downloadUrl = xmlDoc.Root.Element("url")?.Value;

                if (!string.IsNullOrEmpty(latestVersion) && !string.IsNullOrEmpty(downloadUrl) && latestVersion != CurrentVersion)
                {
                    // 獲取當(dāng)前程序名稱
                    string currentProcessName = Process.GetCurrentProcess().ProcessName;

                    // 啟動(dòng)更新程序并傳遞當(dāng)前程序名稱
                    string arguments = $"--url \"{downloadUrl}\" --launch \"{MainProgramRelativePath}\" --current \"{currentProcessName}\"";
                    _ = Process.Start(CustConst.AppNmae, arguments);

                    // 關(guān)閉當(dāng)前主程序
                    Application.Exit();
                }
            }
        }
        catch (Exception ex)
        {
            _ = MessageBox.Show($"檢查更新失敗:{ex.Message}");
        }
    }
}

2、服務(wù)器配置XML

服務(wù)器上存放一個(gè)XML文件配置當(dāng)前最新版本、安裝包下載地址等,假設(shè)服務(wù)器上的 XML 文件內(nèi)容如下:

<?xml version="1.0" encoding="utf-8"?>
<update>
    <version>1.0.2</version>
    <url>https://example.com/yourfile.zip</url>
</update>

主程序調(diào)用更新檢查

主程序可以通過定時(shí)器或者手動(dòng)調(diào)用檢查更新的邏輯,博主使用定時(shí)檢查更新:

internal static class AutoUpdaterHelp
{
    private static readonly System.Timers.Timer timer;
    static AutoUpdaterHelp()
    {
        UpdateChecker.CurrentVersion = "1.0.1";
        UpdateChecker.UpdateUrl = ConfigurationManager.AppSettings["AutoUpdaterUrl"].ToString();
        UpdateChecker.MainProgramRelativePath = "Restart.bat";
        timer = new System.Timers.Timer
        {
            Interval = 10 * 1000//2 * 60 * 1000
        };
        timer.Elapsed += delegate
        {
            UpdateChecker.CheckForUpdates();
        };
    }

    public static void Start()
    {
        timer.Start();
    }

    public static void Stop()
    {
        timer.Stop();
    }
}

思考:性能與安全考量

在實(shí)現(xiàn)自動(dòng)化更新時(shí),還應(yīng)考慮性能和安全因素。例如,為了提高效率,可以添加斷點(diǎn)續(xù)傳功能;為了保證安全,應(yīng)驗(yàn)證下載文件的完整性,例如使用SHA256校驗(yàn)和,這些博主就不做實(shí)現(xiàn)與講解了,目前的功能已經(jīng)完成了基本的自動(dòng)更新邏輯

總結(jié)

自動(dòng)化軟件更新是現(xiàn)代軟件開發(fā)不可或缺的一部分,它不僅能顯著提升用戶體驗(yàn),還能減輕開發(fā)者的維護(hù)負(fù)擔(dān)。

通過上述C#代碼示例,你可以快速搭建一個(gè)基本的自動(dòng)化更新框架,進(jìn)一步完善和定制以適應(yīng)特定的應(yīng)用場景。


閱讀原文:原文鏈接?


該文章在 2025/5/6 15:21:10 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲(chǔ)管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved