[WPF 學習] 19. 增量更新


不管是ClickOnce發布還是生成單個文件的發布都是全量更新,當引用的nuget包較多的時候,重復上傳和下載的內容就比較多,所以需要增量更新。

一、在數據庫增加一個表

CREATE TABLE [dbo].[TApp](
	[Version] [int] IDENTITY(1,1) NOT NULL,
	[Data] [varbinary](max) NOT NULL,
 CONSTRAINT [PK_TApp] PRIMARY KEY CLUSTERED 
(
	[Version] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

就兩列,Version列存放自增長版本號,Data列存放更新的數據。
二、發布

        /// <summary>
        /// 發布
        /// </summary>
        /// <param name="path">發布的目標地址</param>
        /// <returns></returns>
        public static void Publish(string path)
        {
            if (!Directory.Exists(path))
            {
                MessageBox.Show("目標地址不存在");
                return;
            }
            var pathLast = Path.Combine(path, "Last");//保存最后一次發布的文件的文件夾
            if (!Directory.Exists(pathLast))
            {
                Directory.CreateDirectory(pathLast);
                PathCopy(path, pathLast);
                MessageBox.Show("沒有需要發布的內容");
                return;
            }

            List<KeyValuePair<string, byte[]>> items = new List<KeyValuePair<string, byte[]>>();
            foreach (var fullFilename in Directory.GetFiles(path))
            {
                var filename = Path.GetFileName(fullFilename);
                var lastFilename = Path.Combine(pathLast, filename);
                var buffer = File.ReadAllBytes(fullFilename);
                if (File.Exists(lastFilename))
                {
                    var lastBuffer = File.ReadAllBytes(lastFilename);
                    if (buffer.SequenceEqual(lastBuffer))
                        continue;
                }
                File.WriteAllBytes(lastFilename, buffer);
                items.Add(new KeyValuePair<string, byte[]>(filename, buffer));
            }
            if (items.Count == 0)
            {
                MessageBox.Show("沒有需要發布的內容");
                return;
            }


            #region 壓縮一下
            var jsonString = JsonSerializer.Serialize(items);
            using MemoryStream instream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
            using MemoryStream outstream = new MemoryStream();
            using DeflateStream defstream = new DeflateStream(outstream, CompressionMode.Compress);
            instream.CopyTo(defstream);
            defstream.Close();
            var data = outstream.ToArray();
            #endregion





            using SqlConnection cn = new SqlConnection(@"Data Source=.\sqlexpress;initial Catalog=DBApp;integrated Security=True");
            var cmd = cn.CreateCommand();
            cmd.CommandText = "insert into tapp values (@Data)";
            cmd.Parameters.AddWithValue("@Data", data);
            cn.Open();
            cmd.ExecuteNonQuery();

            MessageBox.Show("發布成功");
        }
        /// <summary>
        /// 復制文件夾
        /// </summary>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        private static void PathCopy(string source, string destination)
        {
            foreach (var filename in Directory.GetFiles(source))
                File.Copy(filename, Path.Combine(destination, Path.GetFileName(filename)), true);
        }

三、客戶端更新

        public static void Update()
        {
            var currentPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
            var filenameVersion = Path.Combine(currentPath, "version.txt");
            int clientVersion = 0;
            if (File.Exists(filenameVersion))
                clientVersion = int.Parse(File.ReadAllText(filenameVersion));


            using SqlConnection cn = new SqlConnection(@"Data Source=.\sqlexpress;initial Catalog=DBApp;integrated Security=True");
            cn.Open();
            var cmd = cn.CreateCommand();



            #region 獲取需要更新的內容
            List<KeyValuePair<int, byte[]>> kvs = new List<KeyValuePair<int, byte[]>>();
            cmd.CommandText = $"select * from tapp where version>{clientVersion}";
            var dr = cmd.ExecuteReader();
            while (dr.Read())
                kvs.Add(new KeyValuePair<int, byte[]>(dr.GetInt32(0), (byte[])dr[1]));
            dr.Close();
            if (kvs.Count == 0)
            {
                MessageBox.Show("沒有需要更新的內容");
                return;
            }
            #endregion


            var updatePath = Path.Combine(currentPath, "U" + DateTime.Now.Ticks);
            Directory.CreateDirectory(updatePath);

            foreach (var kv in kvs)
            {
                #region 解壓
                using MemoryStream ms = new MemoryStream(kv.Value);
                using MemoryStream ms2 = new MemoryStream();
                using DeflateStream defStram = new DeflateStream(ms, CompressionMode.Decompress);
                defStram.CopyTo(ms2);
                defStram.Close();
                var buffer = ms2.ToArray();
                #endregion

                var jsonString = Encoding.UTF8.GetString(buffer);
                var items = JsonSerializer.Deserialize<List<KeyValuePair<string, byte[]>>>(jsonString);
                foreach (var item in items)
                    File.WriteAllBytes(Path.Combine(updatePath, item.Key), item.Value);
            }

            File.WriteAllText(filenameVersion, kvs.Max(ii => ii.Key).ToString());//更新客戶端版本號


            #region 生成並運行bat文件
            var batstr = $@"timeout /t 3
taskkill /pid {Process.GetCurrentProcess().Id}
copy {updatePath} {currentPath}
del {updatePath} /Q
rd {updatePath}
{Process.GetCurrentProcess().MainModule.FileName}
";
            var filenameBat = Path.Combine(currentPath, "update.bat");
            File.WriteAllText(filenameBat, batstr);
            App.Current.Shutdown();
            Process.Start(filenameBat);
            #endregion
        }

四、測試一下

添加兩個按鈕,對應的click事件如下:

        private void BtnPublish_Click(object sender, RoutedEventArgs e)
        {
            Publish(@"D:\TestHot\ConsoleApp1\WpfUpdate\bin\Release\net5.0-windows\publish");
        }

        private void BtnUpdate_Click(object sender, RoutedEventArgs e)
        {
            Update();
        }

最后就是vs發布、單擊發布按鈕、單擊更新按鈕...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM