目录
这一篇就着重写一下客户端的代码,客户端主要实现的有:启动后检测本地的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自动更新程序的资料请关注中国红客联盟其它相关文章! |