本通用自动更新模块适合所有Windows桌面程序的自动更新,不论语言,无论Winform还是wpf。

一、工作流程:
1. 主程序A调起升级程序B
2. B从服务器获取更新程序列表,打印更新信息。
3. B杀死A进程(此步骤可以放在步骤2~5任意位置)
4. B根据更新信息中指示的地址,下载更新程序包(.zip文件)
5. 解压缩.zip文件到一个新创建的文件夹
6. 将解压后的文件拷贝到原始文件目录,做替换。
7. 删除下载的.zip文件以及解压后创建的文件夹
8. B打开A

二、源码介绍:

升级程序B的实现:

更新信息列表用于存储版本信息,以及更新说明信息。通常为json或xml文件。本文为json文件。

存储列表信息的类

public class UpdateItem
{
public string Version { get; set; } //版本号
public string UpdateContent { get; set; } //更新信息
public string DownloadUri { get; set; } //更新包的下载地址
public string Time { get; set; } //更新时间
public string Size { get; set; } //更新包大小
}

获取更新信息使用WebClient.DownloadData(Uri),其中使用Newtonsoft.Json进行json序列化及反序列化。

WebClient client = new WebClient();
byte[] data = client.DownloadData(uri);
//json转为UpdateItem类对象
UpdateInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<UpdateItem>(Encoding.UTF8.GetString(data));

获取更新信息以后在界面上进行输出。
下面介绍一下生成更新信息的json文件并使用FTP上传到服务器的代码。json文件也可以手动写,手动上传。不是重点,不想看可以跳到下一部分。

UpdateItem UpdateInfo = new UpdateItem();
... //赋值
string json = JsonConvert.SerializeObject(UpdateInfo);
//连接服务器
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://...");
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential("账号", "密码");
// 复制字符
byte[] fileContents = Encoding.UTF8.GetBytes(json);
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();

下载更新包zip文件

下载使用WebClient.DownloadFile(Uri, string)

string dir = System.IO.Directory.GetCurrentDirectory();  //程序所在文件夹路径
string zipfile = System.IO.Path.Combine(dir, "file.zip"); //下载后zip文件的完整路径 WebClient client = new WebClient();
client.DownloadFile(UpdateInfo.DownloadUri, zipfile);
return true;

解压缩zip文件

解压缩需要用到System.IO.Compression.ZipFile,需要.NET4.5及以上。如果用不了(找不到ZipFile),请检查是否已添加引用System.IO.Compression.FileSystem程序集。

代码只有一行,两个参数分别为zip文件完整路径,解压后的文件夹完整路径。

ZipFile.ExtractToDirectory(zipfile, extractPath);

使用第三方压缩软件生成的.zip文件有可能会解压失败,建议使用下方代码生成。两个参数分别为需要压缩的文件夹完整路径,生成的zip文件完整路径。

ZipFile.CreateFromDirectory(startPath, zipfile);

拷贝解压后的文件到原始目录

foreach (string item in Directory.GetFiles(extractPath))
{
File.Copy(item, System.IO.Path.Combine(dir, System.IO.Path.GetFileName(item)), true);
}

删除临时文件

File.Delete(zipfile);
DirectoryInfo di = new DirectoryInfo(extractPath);
di.Delete(true);

B进程杀死A进程

string appname = "file"; //A名字,不要路径,不要.exe
Process[] processes = Process.GetProcessesByName(appname);
foreach (var p in processes)
p.Kill();

B进程调起A进程

System.Diagnostics.Process.Start(@"path");  //完整路径

主要流程就是这些,建议用异步操作实现。
现在上号比较少,私信很多要代码的都没回…以后都会把完整代码附上的。
下面是完整代码。

private Uri uri = new Uri(@"http://...");  //更新信息列表文件路径
private UpdateItem UpdateInfo; //UpdateItem类的定义在前面第一部分说明 public MainWindow()
{
InitializeComponent();
LoadingData();
} //用户按下更新按钮
private async void Button_Click(object sender, RoutedEventArgs e)
{
//下载
Tb_State.Text = "正在下载新版本文件,请耐心等待";
string dir = System.IO.Directory.GetCurrentDirectory();
string zipfile = System.IO.Path.Combine(dir, "File.zip");
bool success = await Task.Run(() =>
{
try
{
WebClient client = new WebClient();
client.DownloadFile(UpdateInfo.DownloadUri, zipfile);
return true;
}
catch (Exception)
{
return false;
}
}); if (success)
Tb_State.Text = "文件已下载,正在复制文件";
else
{
Tb_State.Text = "下载新版本文件失败,请重试";
return;
} //杀死主程序进程
string appname = "File";
Process[] processes = Process.GetProcessesByName(appname);
foreach (var p in processes)
p.Kill(); //解压缩+拷贝+删除
bool success2 = await Task.Run(() =>
{
try
{
string extractPath = System.IO.Path.Combine(dir, "NewVersion");
ZipFile.ExtractToDirectory(zipfile, extractPath);
foreach (string item in Directory.GetFiles(extractPath))
File.Copy(item, System.IO.Path.Combine(dir, System.IO.Path.GetFileName(item)), true);
File.Delete(zipfile);
DirectoryInfo di = new DirectoryInfo(extractPath);
di.Delete(true);
return true;
}
catch (Exception)
{
return false;
}
}); if (success2)
Tb_State.Text = "更新完成,您可以点击下方按钮启动应用";
else
Tb_State.Text = "复制更新文件出错,请重试";
} //读取更新列表文件
private async Task<bool> LoadingData()
{
Tb_State.Text = "正在下载更新文件信息";
bool success = await Task.Run(() =>
{
try
{
WebClient client = new WebClient();
byte[] data = client.DownloadData(uri);
UpdateInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<UpdateItem>(Encoding.UTF8.GetString(data));
return true;
}
catch (Exception)
{
return false;
}
}); if (success)
Tb_State.Text = "已获取新版本信息,可进行更新";
else
Tb_State.Text = "无法获取更新信息";
return success;
} //更新完成,更新程序B调起主程序A
private void Btn_Open_Click(object sender, RoutedEventArgs e)
{
System.Diagnostics.Process.Start(@"D:\..."); //A程序完整路径
}

再贴一个用于下载过程中,能实时显示已下载文件大小的代码
此部分需写在下载部分之前。

System.Windows.Threading.DispatcherTimer dt = new System.Windows.Threading.DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(100); //100毫秒
dt.Tick += (x, y) => {
if (File.Exists(zipfile) == false)
return;
string size = ((new FileInfo(zipfile).Length) / 1024.0 / 1024).ToString("f2");
if (download == false) //是否下载完毕
Tb_State.Text = size + "MB / " + UpdateInfo.Size; //输出:已下载/总大小
else
dt.Stop();
};
dt.Start();

代码部分执行时,再次执行代码可能会报错。可能原因包括下载zip文件后未删除再次下载报错等。如要做项目还有很多地方需要进行判断,如检测路径的合法性等。为了代码便于阅读,没有加入这些错误检测部分,需自行补充。几乎所有操作前都应判断路径合法性,以及目标位置的文件是否存在(是否需要先删除)等。只能说是在输入合法的情况下,完整执行此代码是没有问题的。

代码通过Visual Studio 2019测试,.NET4.5。

Windows程序通用自动更新模块(C#,.NET4.5以上)的更多相关文章

  1. Winform开发框架之通用自动更新模块(转)

    在网络化的环境中,特别是基于互联网发布的Winform程序,程序的自动更新功能是比较重要的操作,这样可以避免挨个给使用者打电话.发信息通知或者发送软件等,要求其对应用程序进行升级.实现程序的自动更新, ...

  2. winform 通用自动更新程序

    通用自动更新程序 主要功能: 1. 可用于 C/S 程序的更新,集成到宿主主程序非常简单和配置非常简单,或不集成到主程序独立运行. 2. 支持 HTTP.FTP.WebService等多种更新下载方式 ...

  3. WinForm通用自动更新器AutoUpdater项目实战

    一.项目背景介绍 最近单位开发一个项目,其中需要用到自动升级功能.因为自动升级是一个比较常用的功能,可能会在很多程序中用到,于是,我就想写一个自动升级的组件,在应用程序中,只需要引用这个自动升级组件, ...

  4. 分析nuget源码,用nuget + nuget.server实现winform程序的自动更新

    源起 (个人理解)包管理最开始应该是从java平台下的maven开始吧,因为java的开发大多数是基于开源组件开发的,一个开源包在使用时很可能要去依赖其他的开源包,而且必须是特定的版本才可以.以往在找 ...

  5. Android应用程序的自动更新升级(自身升级、通过tomcat)(转)

    Android应用程序的自动更新升级(自身升级.通过tomcat) http://blog.csdn.net/mu0206mu/article/details/7204746 刚入手android一个 ...

  6. 【实用篇】Android之应用程序实现自动更新功能

    我个人用的是友盟提供的自动更新组件,因此在这里只描述如何实用友盟提供的组件来完成程序的自动更新,步骤如下: 1.登录友盟官网,点击注册一个友盟账号. 2.注册成功后将会自动进入到添加新应用界面,选择添 ...

  7. 安卓程序代写 网上程序代写[原]Android应用的自动更新模块

    软件的自动更新一般都与Splash界面绑定在一起, 由于需要维护的软件界面很复杂, 一个Activity中嵌入ViewPager, 并且逻辑比较复杂, 索性重新写一个Activity, 现在的软件都很 ...

  8. windows下svn自动更新

    配置hooks下post-commit.bat文件,文件内容如下 @echo offSET REPOS=%1SET REV=%2SET DIR=%REPOS%/hooksSET PATH=%PATH% ...

  9. 【Android 应用开发】Android应用的自动更新模块

    . 作者 :万境绝尘  转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/18964835 . 软件的自动更新一般都与Splash界 ...

随机推荐

  1. Sql Server 数据把列根据指定的内容拆分数据

    今天由于工作需要,需要把数据把列根据指定的内容拆分数据 其中一条数据实例 select id , XXXX FROM BIZ_PAPER where  id ='4af210ec675927fa016 ...

  2. [日常摸鱼]poj1741Tree-点分治

    还有两天就要去FJWC啦- 题意:一颗无根树,$k$为给定常数,求树上距离不超过$k$的点对的数量,多组数据,$n \leq 10^4$. 应该是点分治经典题~ 一般对于无根树我们都可以把它转变成有根 ...

  3. 高可用K8S构建3master+3node+keepalived+haproxy

    视频地址:https://www.bilibili.com/video/BV1w4411y7Go?p=66 所需安装包在视频评论区 安装准备 系统: CentOS-7-x86_64-Minimal-1 ...

  4. canvas可视化效果之内阴影效果

    canvas可视化效果之内阴影效果 楔子 在之前的一个轨道交通可视化项目中,运用到了很多绘制技巧. 可以参考 之前的一篇文章 <利用canvas阴影功能与双线技巧绘制轨道交通大屏项目效果> ...

  5. 每日CSS_纯CSS制作进度条

    每日CSS_纯CSS制作进度条 2020_12_26 源码 1. 代码解析 1.1 html 代码解析 设置整个容器 <div class="container"> . ...

  6. 【老孟Flutter】2020年总结

    2020年是我经历的最不平凡的一年,这一年有遗憾.有收获,有感概,也有庆幸,庆幸自己还活着. 用一句话总结自己的2020,忙并收获着,累并快乐着. <Flutter 实战入门> <F ...

  7. SpringBoot+Vue 前后端合并部署

    前后端分离开发项目 前端vue项目 服务端springboot项目 如何将vue的静态资源整合到springboot项目里,通过启动jar包的方式部署服务. 前端项目执行npm run build 命 ...

  8. [LeetCode]147. Insertion Sort List链表排序

    插入排序的基本思想 把排好的放在一个新的变量中,每次拿出新的,排进去 这个新的变量要有超前节点,因为第一个节点可能会有变动 public ListNode insertionSortList(List ...

  9. 熬夜肝了一周!总结了这套对标阿里P8的java秘籍,限时发布3天!

    前言 最近老是有粉丝私信我说感觉自己学java越来越难了,这其中有刚毕业的应届生说自己的技术找不到满意的工作,也有在学校的大学习说找不到学习方式,更多的是正在工作的java开发人员说是现在的技术更新太 ...

  10. Redis 设计与实现 9:五大数据类型之集合

    集合对象的编码有两种:intset 和 hashtable 编码一:intset intset 的结构 整数集合 intset 是集合底层的实现之一,从名字就可以看出,这是专门为整数提供的集合类型. ...