本通用自动更新模块适合所有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. 用 Roslyn 做个 JIT 的 AOP

    0. 前言 上接:AOP有几种实现方式 接下来说说怎么做AOP的demo,先用csharp 说下动态编织和静态编织,有时间再说点java的对应内容. 第一篇先说Roslyn 怎么做个JIT的AOP d ...

  2. 面试 02-CSS盒模型及BFC

    02-CSS盒模型及BFC #题目:谈一谈你对CSS盒模型的认识 专业的面试,一定会问 CSS 盒模型.对于这个题目,我们要回答一下几个方面: (1)基本概念:content.padding.marg ...

  3. vue第十三单元(指令的作用,指令的钩子函数)

    第十三单元(指令的作用,指令的钩子函数) #课程目标 1.了解自定义指令的应用场景 2.掌握自定义全局和局部指令 3.掌握指令的钩子函数 #知识点 #一.认识自定义指令 除了核心功能默认内置的指令 ( ...

  4. 网络编程-python实现-socket(1.1.1)

    @ 目录 1.不同电脑进程之间如何通信 2.什么是socket 3.创建socket 1.不同电脑进程之间如何通信 利用ip地址 协议 端口 标识网络的进程,网络中的进程通信就可以利用这个标志与其他进 ...

  5. SpringBoot2 整合OAuth2组件,模拟第三方授权访问

    本文源码:GitHub·点这里 || GitEE·点这里 一.模式描述 授权服务 验证第三方服务的身份,验证邮箱用户的身份,记录和管理认证Token,为资源服务器提供Token校验.场景:第三方网站借 ...

  6. MQTT协议 局域网和广域网 云服务器和虚拟主机、VPS SSH和FTP、SFTP

     MQTT协议 MQTT协议就很好的解决了coap存在的问题.MQTT协议是由IBM开发的即时通讯协议,相比来说比较适合物联网场景的通讯协议.MQTT协议采用发布/订阅模式,所有的物联网终端都通过TC ...

  7. C# Json对象数组复杂JObject 序列化

    tatic void Main(string[] args) { //先反序列化看看 string json = "{\"name\": true,\"age\ ...

  8. 二、LINUX文本处理三剑客之grep

    1. grep一般格式:grep [选项] 基本正则表达式 [文件],其中基本正则表达式需要用引号引起来 引号引起来的作用:a.防止被误解为shell命令,b.可以用来查找多个单词组成的字符串 gre ...

  9. Git设置记住账号密码

    Git设置记住账号密码 添加如下配置 [credential] helper = store

  10. 转【深入理解SQL的四种连接-左外连接、右外连接、内连接、全连接】

    转自:https://www.jb51.net/article/39432.htm 1.内联接(典型的联接运算,使用像 =  或 <> 之类的比较运算符).包括相等联接和自然联接.     ...