C# WinForm实现自动更新程序的方法详解

 更新时间:2022年10月18日 09:29:39   作者:Csharp小记  
这一篇就着重写一下客户端的代码,客户端主要实现的有:启动后检测本地的xml文件,然后发送到服务器获取需要更新的文件以及版本列表,感兴趣的小伙伴可以了解一下

这一篇就着重写一下客户端的代码,客户端主要实现的有:启动后检测本地的xml文件,然后发送到服务器获取需要更新的文件以及版本列表。循环下载。下载成功后,备份原始文件->复制到主目录(若失败进行回滚)->修改本地xml文件,更新完成后打开主程序。

开发环境

.NET Core 3.1

开发工具

Visual Studio 2019

实现代码

/// <summary>
        /// 更新自己
        /// </summary>
        private void CopyRun() {

            string runPath = Process.GetCurrentProcess().MainModule.FileName;
            string runName = Path.GetFileName(runPath);

            if(!runName.StartsWith("_")) {
                string copyPath = runPath.Replace(runName, "_" + runName);
                byte[] bytes;
                using(FileStream fileStream = new FileStream(runPath, FileMode.Open, FileAccess.Read)) {
                    bytes = new byte[fileStream.Length];
                    fileStream.Read(bytes, 0, bytes.Length);
                }
                using(FileStream fileStream = new FileStream(copyPath, FileMode.Create, FileAccess.Write)) {
                    fileStream.Write(bytes);
                }

                ProcessStartInfo info = new ProcessStartInfo(copyPath, _runApp);
                Process.Start(info);
                Environment.Exit(0);
            }

        }

        /// <summary>
        /// 更新UI
        /// </summary>
        /// <param name="actoin"></param>
        private void UpdateUI(Action actoin) {
            if(this.InvokeRequired) {
                this.BeginInvoke(actoin);
            }
            else {
                actoin();
            }
        }

        /// <summary>
        /// 获取本地更新地址
        /// </summary>
        /// <returns></returns>
        private string GetUpdateUrl() {
            XElement xele = XElement.Load(updateXml);
            string url = xele.Element("url").Value;
            return url;
        }

        /// <summary>
        /// 获取本地更新文件
        /// </summary>
        /// <returns></returns>
        private string GetUpdateFiles() {
            XDocument xdoc = XDocument.Load(updateXml);
            var files = from f in xdoc.Root.Element("files").Elements() select new { name = f.Attribute("name").Value, version = f.Attribute("version").Value };
            return JsonConvert.SerializeObject(files);
        }

        /// <summary>
        /// 更新完成后修改版本文件
        /// </summary>
        /// <param name="list"></param>
        private void UpdateXml(List<UpdateModel> list) {
            XDocument xdoc = XDocument.Load(updateXml);
            foreach(var model in list) {
                var ele_files = xdoc.Root.Element("files");

                XElement xele = ele_files.Elements().FirstOrDefault(s => s.Attribute("name").Value == model.name);
                if(xele != null) {
                    xele.SetAttributeValue("version", model.version);
                }
                else {
                    XElement addXele = new XElement("file");
                    addXele.SetAttributeValue("name", model.name);
                    addXele.SetAttributeValue("version", model.version);
                    ele_files.Add(addXele);
                }
            }
            xdoc.Save(updateXml);
        }
readonly string _runApp;
        public Form_update(string runApp) {
            InitializeComponent();
            _runApp = runApp;
            //CopyRun();
        }
        readonly string updateXml = Application.StartupPath + "UpdateList.xml";
        private void btn_update_Click(object sender, EventArgs e) {
            #region 设置ui
            btn_update.Enabled = false;
            label_status.Text = "正在更新";
            #endregion

            #region 初始化路径
            string savePath = Application.StartupPath + "temp_update\\";
            string backPath = Application.StartupPath + "temp_back\\";
            if(Directory.Exists(savePath)) {
                Directory.Delete(savePath, true);
            }
            Directory.CreateDirectory(savePath);

            if(Directory.Exists(backPath)) {
                Directory.Delete(backPath, true);
            }
            Directory.CreateDirectory(backPath);

            #endregion

            #region 图标旋转
            int angle = 0;
            Image img = pictureBox1.BackgroundImage;

            System.Threading.Timer timer = new System.Threading.Timer(s => {
                UpdateUI(() => {
                    angle = angle == 360 ? 0 : angle + 10;
                    pictureBox1.BackgroundImage = img.RotateImage(angle);
                });
            }, null, 0, 100);
            #endregion

            #region 下载更新
            string url = GetUpdateUrl();
            bool isSuccess = false;
            Task.Run(() => {
                try {
                    //获取下载列表
                    HttpResult httpResult = HttpUtil.HttpRequest(new HttpItem(url + "GetUpdateFiles", requestData: GetUpdateFiles()));
                    if(httpResult.Status) {
                        UpdateModel_Out output = JsonConvert.DeserializeObject<UpdateModel_Out>(httpResult.HttpStringData);

                        if(output.updateList.Count == 0) {
                            throw new Exception("当前已是最新版本");
                        }

                        UpdateUI(() => {
                            progressBar1.Maximum = output.updateList.Count + 1;
                        });
                        //循环下载文件
                        for(int i = 0; i < output.updateList.Count; i++) {

                            UpdateModel updateModel = output.updateList[i];
                            #region 进度条
                            UpdateUI(() => {
                                label_status.Text = $"正在更新第 {i + 1}/{output.updateList.Count} 个文件,文件名:{updateModel.name}";
                                progressBar1.Value = i + 1;
                            });
                            #endregion

                            #region 下载文件
                            httpResult = HttpUtil.HttpRequest(new HttpItem(url + "DownloadFile", requestData: JsonConvert.SerializeObject(updateModel)));
                            if(httpResult.Status) {
                                using(FileStream fileStream = new FileStream(savePath + updateModel.name, FileMode.Create)) {
                                    fileStream.Write(httpResult.HttpByteData, 0, httpResult.HttpByteData.Length);
                                }
                            }
                            else {
                                throw new Exception(updateModel.name + "下载失败,请重试");
                            }
                            #endregion

                            Task.Delay(1000).Wait();
                        }

                        #region 备份
                        UpdateUI(() => {
                            label_status.Text = "正在备份";
                        });
                        try {
                            File.Copy(updateXml, backPath + "UpdateList.xml");
                            foreach(var file in output.updateList) {
                                if(File.Exists(Application.StartupPath + file.name)) {
                                    File.Copy(Application.StartupPath + file.name, backPath + file.name, true);
                                }
                            }
                        }
                        catch { }
                        #endregion

                        #region 完成更新
                        UpdateUI(() => {
                            label_status.Text = "正在完成更新";
                            progressBar1.Value = progressBar1.Maximum;
                        });
                        string[] files = Directory.GetFiles(savePath);
                        try {
                            #region 更新成功
                            foreach(string file in files) {
                                File.Copy(file, Application.StartupPath + Path.GetFileName(file), true);
                            }
                            Directory.Delete(savePath, true);
                            #region 保存最新版本
                            UpdateXml(output.updateList);
                            isSuccess = true;
                            UpdateUI(() => {
                                label_status.Text = "更新完成";
                            });
                            #endregion
                            #endregion
                        }
                        catch {
                            #region 失败回滚
                            UpdateUI(() => {
                                label_status.Text = "更新失败,正在回滚";
                            });
                            string[] files_back = Directory.GetFiles(backPath);
                            foreach(string file in files_back) {
                                File.Copy(file, Application.StartupPath + Path.GetFileName(file), true);
                            }
                            File.Copy(backPath + "UpdateList.xml", updateXml, true);
                            UpdateUI(() => {
                                label_status.Text = "回滚完成";
                            });
                            return;
                            #endregion
                        }
                        #endregion
                    }
                    else {
                        throw new Exception("获取更新列表失败");
                    }
                }
                catch(Exception ex) {
                    UpdateUI(() => {
                        label_status.Text = "更新失败!" + ex.Message;
                        btn_update.Enabled = true;
                    });
                }
                finally {
                    UpdateUI(() => {
                        timer.Change(-1, -1);
                        pictureBox1.BackgroundImage = img;
                        if(isSuccess) {
                            if(File.Exists(_runApp)) {
                                if(MessageBox.Show("更新完成,是否打开程序", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {
                                    Process.Start(_runApp);
                                }
                                Environment.Exit(0);
                            }
                        }
                    });
                }
            });
            #endregion

        }

        private void btn_close_Click(object sender, EventArgs e) {
            Close();
        }

        private void panel1_Paint(object sender, PaintEventArgs e) {
            Pen pen = new Pen(Color.LightGray);
            e.Graphics.DrawLine(pen, new Point(36, 36), new Point(panel1.Width - 36, 36));
        }

实现效果

代码解析

主要注释已经在代码中标注了,由于基本都是在线程中进行操作的,所以在更新UI的时候封装了UpdateUI方法,然后就是加了一个定时器实现图标的旋转。关于CopyRun(更新自己)方法,就是用来更新自动更新程序本身的,即运行之前复制一份本身,然后启动复制的程序,否则本身正在运行的时候是不能更新自己的。

以上就是C# WinForm实现自动更新程序的方法详解的详细内容,更多关于C# WinForm自动更新程序的资料请关注脚本之家其它相关文章!

相关文章

  • winform开发使用通用多线程基类分享(以队列形式)

    winform开发使用通用多线程基类分享(以队列形式)

    多线程这个概念大家都很熟悉,对于winform的开发人员来说,用的还是多的.但估计都是用Timer,或者backgroundWorker,为大家写了一个多线程的基类,只有你用到多线程拿过来就可以用了
    2013-12-12
  • C# 使用modbus 读取PLC 寄存器地址的方法

    C# 使用modbus 读取PLC 寄存器地址的方法

    今天通过本文给大家介绍C# 使用modbus 读取PLC 寄存器地址的方法,使用的组件Nmodbus,文中通过实例代码给大家介绍的非常详细,需要的朋友参考下吧
    2021-10-10
  • C#使用Process类调用外部exe程序

    C#使用Process类调用外部exe程序

    本文通过两个示例讲解了一下Process类调用外部应用程序的基本用法,并简单讲解了StartInfo属性,有需要的朋友可以参考一下。
    2016-03-03
  • C#实现老板键功能的代码

    C#实现老板键功能的代码

    最近在做项目中遇到需要增加个老板键功能,找一惯的方式,开始从网络下手寻找: 关键字类似”C# 老板键“,一搜,一堆又一堆,然而出来的代码大多数都不是太合适,下面给大家分享下自己的解决方案已经一个网友的解决方案,有需要的小伙伴可以参考下。
    2015-05-05
  • C#使用RichTextBox实现替换文字及改变字体颜色功能示例

    C#使用RichTextBox实现替换文字及改变字体颜色功能示例

    这篇文章主要介绍了C#使用RichTextBox实现替换文字及改变字体颜色功能,结合实例形式洗了C#中RichTextBox组件文字替换及改变字体颜色相关操作技巧,需要的朋友可以参考下
    2019-02-02
  • C#实现对Json字符串处理实例

    C#实现对Json字符串处理实例

    这篇文章主要介绍了C#实现对Json字符串处理,通过一个json实例分析了C#进行JSON操作的方法,需要的朋友可以参考下
    2014-09-09
  • datagridview实现手动添加行数据

    datagridview实现手动添加行数据

    这篇文章主要介绍了datagridview实现手动添加行数据,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • C#利用性能计数器监控网络状态

    C#利用性能计数器监控网络状态

    这篇文章主要为大家详细介绍了C#利用性能计数器监控网络状态的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • C#中的EventHandler观察者模式详解

    C#中的EventHandler观察者模式详解

    这篇文章主要介绍了C# EventHandler观察者模式,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • C# 使用Free Spire.Presentation 实现对PPT插入、编辑、删除表格

    C# 使用Free Spire.Presentation 实现对PPT插入、编辑、删除表格

    小编发现使用.NET组件——Free Spire.Presentation,在C#中添加该产品DLL文件,可以简单快速地实现对演示文稿的表格插入、编辑和删除等操作,具体实现代码大家参考下本文吧
    2017-09-09

最新评论