客户端自动升级组件

作者: 05b0963bb480 | 来源:发表于2018-12-09 08:44 被阅读13次

    目前,我们自己开发的电商管理综合平台,在项目刚刚上线的时候,因为我们引用的第三方控件较多,就没有制作专门安装包,而是直接将发布的程序,拷贝到目标机器,直接运行的,因为采用的.NET语言开发,只要目标机器安装了.NET 框架即可。可在程序发布的初期,当我们部署了大概30台客户端后,发现每次修改后的程序,都要拷贝至目标机器运行时,增加了我们的工作量,也给电商部门使用软件带来了不便。为了解决重复繁琐的升级过程,我们给电商综合管理平台新增了自动升级组件。

    自动升级组件开发步骤

    1. 将要升级的文件发布到WebP站点或者FTP站点;
    2. 将一份包含升级文件配置的xml文件分别放置于web站点和本地客户端目录中,未更新时,两端的xml文件应相同。
    3. 发布程序时,为保证能够方便管理,将程序(程序集)的版本号和文件版本号设置为相同的即可。每次升级时,均需要修改版本号。
    4. 通过本地客户端登陆时,将本地的升级xml文件和Web站点的XML进行比对,如果有变化,则直接下载需要更新的程序,完成升级即可。

    Web站点-文件服务部署

    因为我们的程序是运行在公司内网的,所以,我们选择了直接将发布的升级文件部署为一个web站点,设置匿名访问权限,部署网站完成后,通过内网地址可以访问文件,即说明部署正确。

    开发自动升级组件

    客户端组件前端界面设计

    在winform窗体里,我们拖放一个listView列表和一个下载文件的进度条,就可以完成一个简单的升级界面设计了,再此不在详细描述,具体设计界面如下:


    自动升级界面

    后台关键代码编写

    下载文件
    private void DownUpdateFile()
    {
                this.Cursor = Cursors.WaitCursor;
                mainAppExe = updaterXmlFiles.GetNodeValue("//EntryPoint");
                Process[] allProcess = Process.GetProcesses();
                foreach (Process p in allProcess)
                {
                    if (p.ProcessName.ToLower() + ".exe" == mainAppExe.ToLower())
                    {
                        for (int i = 0; i < p.Threads.Count; i++)
                            p.Threads[i].Dispose();
                        p.Kill();
                        isRun = true;
                        //break;
                    }
                }
                WebClient wcClient = new WebClient();
                for (int i = 0; i < this.lvUpdateList.Items.Count; i++)
                {
                    string UpdateFile = lvUpdateList.Items[i].Text.Trim();
                    string updateFileUrl = updateUrl + lvUpdateList.Items[i].Text.Trim();
                    long fileLength = 0;
                    WebRequest webReq = WebRequest.Create(updateFileUrl);
                    WebResponse webRes = webReq.GetResponse();
                    fileLength = webRes.ContentLength;
                    lbState.Text = "正在下载更新文件,请稍后...";
                    pbDownFile.Value = 0;
                    pbDownFile.Maximum = (int)fileLength;
                    try
                    {
                        Stream srm = webRes.GetResponseStream();
                        StreamReader srmReader = new StreamReader(srm);
                        byte[] bufferbyte = new byte[fileLength];
                        int allByte = (int)bufferbyte.Length;
                        int startByte = 0;
                        while (fileLength > 0)
                        {
                            Application.DoEvents();
                            int downByte = srm.Read(bufferbyte, startByte, allByte);
                            if (downByte == 0) { break; };
                            startByte += downByte;
                            allByte -= downByte;
                            pbDownFile.Value += downByte;
                            float part = (float)startByte / 1024;
                            float total = (float)bufferbyte.Length / 1024;
                            int percent = Convert.ToInt32((part / total) * 100);
                            this.lvUpdateList.Items[i].SubItems[2].Text = percent.ToString() + "%";
                        }
                        string tempPath = tempUpdatePath + UpdateFile;
                        CreateDirtory(tempPath);
                        FileStream fs = new FileStream(tempPath, FileMode.OpenOrCreate, FileAccess.Write);
                        fs.Write(bufferbyte, 0, bufferbyte.Length);
                        srm.Close();
                        srmReader.Close();
                        fs.Close();
                    }
                    catch (WebException ex)
                    {
                        MessageBox.Show("更新文件下载失败!" + ex.Message.ToString(), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                InvalidateControl();
                this.Cursor = Cursors.Default;
     }
    
    界面初始化
    private void FrmUpdate_Load(object sender, EventArgs e)
    {
                btnFinish.Visible = false;
                string localXmlFile = Application.StartupPath + "\\UpdateList.xml";
                string serverXmlFile = string.Empty;
                try
                {
                    //从本地读取更新配置文件信息
                    updaterXmlFiles = new XmlFiles(localXmlFile);
                }
                catch
                {
                    MessageBox.Show("配置文件出错!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    this.Close();
                    return;
                }
                //获取服务器地址
                updateUrl = updaterXmlFiles.GetNodeValue("//Url");
                AppUpdater appUpdater = new AppUpdater();
                appUpdater.UpdaterUrl = updateUrl + "/UpdateList.xml";
                //与服务器连接,下载更新配置文件
                try
                {
                    tempUpdatePath = Environment.GetEnvironmentVariable("Temp") + "\\" + "_" + updaterXmlFiles.FindNode("//Application").Attributes["applicationId"].Value + "_" + "y" + "_" + "x" + "_" + "m" + "_" + "\\";
                    appUpdater.DownAutoUpdateFile(tempUpdatePath);
                }
                catch
                {
                    MessageBox.Show("与服务器连接失败,操作超时!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    this.Close();
                    return;
                }
                //获取更新文件列表
                Hashtable htUpdateFile = new Hashtable();
                serverXmlFile = tempUpdatePath + "\\UpdateList.xml";
                if (!File.Exists(serverXmlFile))
                {
                    return;
                }
                availableUpdate = appUpdater.CheckForUpdate(serverXmlFile, localXmlFile, out htUpdateFile);
                if (availableUpdate > 0)
                {
                    for (int i = 0; i < htUpdateFile.Count; i++)
                    {
                        string[] fileArray = (string[])htUpdateFile[i];
                        lvUpdateList.Items.Add(new ListViewItem(fileArray));
                    }
                }
    }
    
    下一步按钮事件
    private void btnNext_Click(object sender, EventArgs e)
    {
          if (availableUpdate > 0)
          {
                   Thread threadDown = new Thread(new ThreadStart(DownUpdateFile));
                   threadDown.IsBackground = true;
                   threadDown.Start();
          }
          else
          {
                   MessageBox.Show("没有可用的更新!", "自动更新", MessageBoxButtons.OK, MessageBoxIcon.Information);
                   return;
          }
    }
    

    UpdateList.xml

    代码里需要用到的更新文件模板如下:


    UpdateList.xml

    红色标记的Url 就是更新文件所在的web站点地址。
    自动更新组件效果图


    自动升级

    当系统登陆时,自动检查,发现升级文件后,运行自动升级组件,如上图所示,直接点击下一步,下载文件,即可完成程序文件升级操作。

    特别说明

    此次分享的自动升级组件,是目前最简单的一种客户端升级方案,对于内网使用的软件,此方案可以满足要求,如果客户端是网络版的,则需要考虑更多安全方面的因素。比如,为了增加升级服务的安全性,自动升级的URL地址可加密存储在本地,将需要升级的文件压缩加密存放于FTP服务器,通过FTP服务下载文件,使用密码解压文件。

    相关文章

      网友评论

        本文标题:客户端自动升级组件

        本文链接:https://www.haomeiwen.com/subject/mgalcqtx.html