本通用自动更新模块适合所有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. IDEA创建maven项目很慢的问题解决方式

    问题现象:刚转IDEA开发,发现创建maven项目,非常慢. 解决方式: 构建maven项目添加参数,要不然非常慢,会卡住-DarchetypeCatalog=internal 自动导入包,codin ...

  2. MongoDB加索引DB崩溃的问题

    项目原因,最近在对MongoDB进行数据存储优化   原有问题: 日志数据量比较大,存到一张表,需要手工定时删除数据,且删除数据时间按天算 数据会定时打包到HDFS,查询时间很慢,需要优化 机器内存占 ...

  3. 网络 IO 模型简单介绍

    一.同步阻塞 IO(BIO) 当用户线程调用了 read 系统调用,内核(kernel)就开始了 IO 的第一个阶段:准备数据.很多时候,数据在一开始还没有到达(比如,还没有收到一个完整的Socket ...

  4. MySQL锁(三)行锁:幻读是什么?如何解决幻读?

    概述 前面两篇文章介绍了MySQL的全局锁和表级锁,今天就介绍一下MySQL的行锁. MySQL的行锁是各个引擎内部实现的,不是所有的引擎支持行锁,例如MyISAM就不支持行锁. 不支持行锁就意味着在 ...

  5. wsgi和asgi的关系

    什么是WSGI #CGI CGI(Common Gateway Interface,通用网关接口),定义客户端与Web服务器的交流方式的一个程序,例如正常情况下客户端发送过来一个请求,根据HTTP协议 ...

  6. 一位弱校选手的oi经历

    锦瑟无端五十弦,一弦一柱思华年. 这只是一位不知道什么时候就要退役的oier在一节晚自习的时候写的无聊东西 曾经也想好好写一写自己的oi历程,也许会有人看,不过因为自己懒加上文笔差也一直没写,直到昨天 ...

  7. javaScript继承的几种实现方式?

    js继承总共分成5种,包括构造函数式继承.原型链式继承.组合式继承.寄生式继承和寄生组合式继承. 构造函数式继承 首先来看第一种,构造函数式继承,顾名思义,也就是利用函数去实现继承:构造函数继承,使用 ...

  8. SQL:我为什么慢你心里没数吗?

    SQL 语句执行慢的原因是面试中经常会被问到的,对于服务端开发来说也是必须要关注的问题. 在生产环境中,SQL 执行慢是很严重的事件.那么如何定位慢 SQL.慢的原因及如何防患于未然.接下来带着这些问 ...

  9. [EF] - 作为DAL层遇到的问题

    今天在部署一个经典三层的项目的时候,用到了EntityFramework,碰到几个问题: 在用EntityFramework将数据库导入到DAL层后,在BL层引用该DAL后,在测试项目的时候,想要查询 ...

  10. Java学习_Java快速入门

    Java简介 安装完JDK后,需要设置一个JAVA_HOME的环境变量,它指向JDK的安装目录.在Windows下,它是安装目录,类似: C:\Program Files\Java\jdk-15 把J ...