艾伟_转载:简单的自动更新程序实现

简介: 本文将演示一种桌面程序自动更新方案,其步骤比较多,但原理非常简单,通用性尚可,对于小型应用来说,直接拿去就可以用了。原理服务器端的结构是这样的:其工作原理如下:Update.asmx仅提供一个功能,就是检测是否需要更新,在需要更新的时候就返回一个更新地址,通常情况下返回的地址就是Download.ashx,而在某些特殊情况下,也可以修改服务端使之从其他Url提供更新下载。

image 本文将演示一种桌面程序自动更新方案,其步骤比较多,但原理非常简单,通用性尚可,对于小型应用来说,直接拿去就可以用了。

原理

服务器端的结构是这样的:

image

其工作原理如下:

Update.asmx仅提供一个功能,就是检测是否需要更新,在需要更新的时候就返回一个更新地址,通常情况下返回的地址就是Download.ashx,而在某些特殊情况下,也可以修改服务端使之从其他Url提供更新下载。检测是否需要更新的的具体做法是:首先获取Updata目录中的主程序版本号,再获取数据库中的最新版本号,两者对比。如果相同则直接与客户端提供的版本号相对比并返回结果;如果不同则将主程序版本号写入数据库,然后生成新的更新文件包,直接向客户端返回更新地址。

Download.ashx的功能仅仅是将最新版本更新文件包输出。

而客户端部分包含主程序、Update.exe以及其他附属文件,更新时由主程序检测并下载更新,在主程序退出时,如有更新并已成功下载,则调用Update.exe完成解包及更新覆盖工作。需注意的是:Update.exe永远不能被更新,因为它无法更新其自身,所以服务端更新时也不要将Update.exe纳入更新包。

下面就是来实际编写一个自动更新解决方案:

服务器端

首先建立一个Web服务项目,项目名为“自动更新服务”:

image

添加一数据库,名为Database.mdf:

image

在数据库中创建新的数据库关系图,并如下设计数据库表:

image

创建一个Ado.Net Entity Data Model,名为Model.edmx:

image

从刚才的建立的数据库中生成模型:

image

在Web.Config的appSettings节点中新增两个节点,用以设置更新程序的主文件名及更新包下载地址:

<appSettings>
    <add key="主程序文件名" value="MyApp.exe"/>
    <add key="更新包下载地址" value="Download.ashx"/>

  appSettings>

引入一个GZip类用以打包(该类的源码将在文章末尾随本文示例源代码一并提供):

image

添加一个新的Web服务,名为Update.asmx:

image

书写如下代码:

[WebMethod]
public string GetUpdate(string ClientVerison)
{
    if (获取最新版本() != ClientVerison)
    {
        return System.Web.Configuration.WebConfigurationManager.AppSettings["更新包下载地址"];
    }
    return null;
}
static string 获取最新版本()
{
    string v = 获取文件版本(HttpContext.Current.Server.MapPath(string.Format("~/App_Data/Up
date/{0}"
, System.Web.Configuration.WebConfigurationManager.AppSettings["主程序文件名"]))); using (var c = new DatabaseEntities()) { //从数据库取得最新版本信息 var q = c.UpdateVersion.OrderByDescending(f => f.PublicTime).FirstOrDefault(); if (q == null || v != q.Version) { //数据库中的版本与当前主程序版本不一致时,以主程序版本为准,写入数据库,并生成新的更新文件包 var d = new UpdateVersion() { Version = v, PublicTime = DateTime.Now }; c.AddToUpdateVersion(d); c.SaveChanges(); 打包更新文件(HttpContext.Current.Server.MapPath("~/App_Data/Update/"), HttpContext
.
Current.Server.MapPath("~/App_Data/Update.gzip")); } } return v; } public static void 打包更新文件(string 打包目录, string 输出文件) { GZip.压缩(输出文件, Directory.GetFiles(打包目录).Concat(Directory.GetDirectories(打包目录)).
ToArray()); }
public static string 获取文件版本(string 文件路径) { FileVersionInfo f = FileVersionInfo.GetVersionInfo(文件路径); return f.FileVersion; }

创建Download.ashx,用以输出更新文件包:

image

代码:

public void ProcessRequest(HttpContext context)
{
    context.Response.ContentType = "application/zip";
    context.Response.WriteFile(context.Server.MapPath("~/App_Data/Update.gzip"));
}

服务端至此就编写完毕了。

客户端

新建一个WinForm应用程序项目,名为Update:

image

建好之后直接删掉Form1.cs吧,此程序不需要界面,在Program.cs中写代码就可以了。

同样需要引入GZip类用于解包:

image

然后编写代码:

[STAThread]
static void Main()
{
    try
    {
        var d = DateTime.Now;
        while (DateTime.Now.Subtract(d).TotalSeconds < 10) Application.DoEvents();
        GZip.解压缩(Path.Combine(Application.StartupPath, "update.data"), Application.
StartupPath); } catch { } }

这里的作用就是等待10秒,然后解包update.data文件,覆盖到当前目录中。

现在来建立主程序,主程序是WinForm、命令行、WPF都可以,我们新建一个WPF应用程序,命名为MyAPP:

image

为程序添加服务引用:

image

这里的地址使用的是本地的调试地址。

为了检测主程序自身的版本号,还需要添加对System.Windows.Forms的引用。

然后开始设计界面,这里仅为演示更新操作,所以界面上只是简单的设计了更新相关的提示、操作控件:

image

代码为:

 x:Class="MyApp.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="377" Loaded="Window_Loaded" Closed="Window_Closed">
            Height="1*" />
            Height="1*" />
            Height="1*" />
        Margin="0" Name="label1" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">检测到新版本,是否下载? 
        
        Grid.Row="2" Margin="0" Name="label2" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Hidden">更新包已下载完毕,在程序关闭后将自动执行更新操作。 

需注意的是,这里控件都被设置为Visibility="Hidden",我们将会在需要时再将其显示出来。

编写后台代码:

public Uri DownloadUri
{
    get
    {
        return _DownloadUri;
    }
    set
    {
        _DownloadUri = value;
    }
}
private Uri _DownloadUri;
public bool UpdateReady
{
    get
    {
        return _UpdateReady;
    }
    set
    {
        _UpdateReady = value;
    }
}
private bool _UpdateReady;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    var u = new MyApp.ServiceReference.UpdateSoapClient();
    var s=u.GetUpdate(System.Windows.Forms.Application.ProductVersion);
    if (!string.IsNullOrEmpty(s))
    {
        //获取相对于Web服务所在Uri的Uri
        DownloadUri = new Uri(u.Endpoint.ListenUri, s);
        label1.Visibility = button1.Visibility = Visibility.Visible;
    }
}
private void button1_Click(object sender, RoutedEventArgs e)
{
    var c = new WebClient();
    c.DownloadFile(DownloadUri, System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, "update.data"));
    UpdateReady = true;
    label2.Visibility = Visibility.Visible;
}
private void Window_Closed(object sender, EventArgs e)
{
    if (UpdateReady)
    {
        Process.Start(System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, 
"update.exe"
)); } }

 

测试

现在将主程序、附属文件和Update.exe放在一起,并将主程序及附属文件复制一份放到服务器端的App_data/Update/目录中,再添加一个“更新说明.txt”:

image

然后启动客户端程序进行测试,应该看到程序界面里什么都没有,因为客户端和服务器端程序版本是一致的。

现在我们修改客户端版本号为1.0.0.1:

image

然后重新编译程序。

因为服务器仅仅是判断版本号是否不同,而不是哪个更高,所以不仅仅是升级,降级更新也是可以的,我们来测试一下:

image

找到所谓的新版本了^^,点开始下载:

image

下载完成,这时目录里就有update.data这个文件了。

现在关闭程序,等待10秒,让Update.exe完成更新:

image

可以看到,程序被降级为1.0.0.0了,而且那个“更新说明.txt”也被更新出来了。

下载

示例源代码:http://www.uushare.com/user/icesee/file/2338431

本文的XPS版本:http://www.uushare.com/user/icesee/file/2338436

目录
相关文章
|
人工智能 监控 算法
java智慧城管源码 AI视频智能分析 可直接上项目
Java智慧城管源码实现AI视频智能分析,适用于直接部署项目。系统运用互联网、大数据、云计算和AI提升城市管理水平,采用“一级监督、二级指挥、四级联动”模式。功能涵盖AI智能检测(如占道广告、垃圾处理等)、执法办案、视频分析、统计分析及队伍管理等多个模块,利用深度学习优化城市管理自动化和智能化,提供决策支持。
610 4
java智慧城管源码 AI视频智能分析 可直接上项目
|
存储 运维 JavaScript
SaaS云HIS平台源码 采用云部署模式,部署一套可支持多家医院共同使用
通过基于SaaS模式的医院管理系统,院内的医护人员、患者可快速建立互联协同。不仅如此,通过SaaS模式提供的解决方案,医院机构可实现远程医疗,从而为不同地区的患者带来优质医疗资源,促进医疗公平。
380 5
|
C# 开发者 Windows
不可不知的WPF转换(Transform)
【9月更文挑战第14天】在 Windows Presentation Foundation(WPF)中,转换(Transform)是一种强大的工具,允许开发者以多种方式操纵图形和界面元素的外观与位置。主要类型包括平移、旋转、缩放和倾斜转换。通过组合这些转换,可以实现更复杂的效果,并且可以与 WPF 的动画系统结合,创建动态界面效果。掌握 WPF 转换是成为优秀开发者的必备技能之一。
268 6
|
人工智能 自然语言处理 搜索推荐
博物馆地图导览系统:GIS与蓝牙定位技术实现地图导览与语音解说功能
维小帮博物馆地图导览系统结合GIS地图、蓝牙定位及智能语音解说,为访客提供沉浸式导览。系统采用自研地图引擎,精准构建三维模型,支持路径规划与个性化定制。蓝牙技术实现高精度室内定位及自动触发语音解说功能,无需手动操作。系统还支持多语言解说与AI语音生成,提升参观体验。目前已在多个博物馆应用并获好评。期待与您共同推进文化科技的融合发展!
394 3
|
中间件 数据挖掘 API
ERP系统的系统集成与接口管理:实现高效协同
【7月更文挑战第29天】 ERP系统的系统集成与接口管理:实现高效协同
1077 0
|
Linux 开发者
【亮剑】Linux系统中的四种文件锁定机制:flock、fcntl、lockfile和flockfile,用于多进程环境下协调共享资源访问,防止数据损坏和竞争条件
【4月更文挑战第30天】本文介绍了Linux系统中的四种文件锁定机制:flock、fcntl、lockfile和flockfile,用于多进程环境下协调共享资源访问,防止数据损坏和竞争条件。flock适合脚本,fcntl提供底层灵活性,lockfile用于管理锁定文件,flockfile则结合两者功能。选择锁定策略时需考虑应用场景,如脚本可选flock,复杂需求则用fcntl。理解并正确使用这些工具对保证系统稳定性和数据一致性至关重要。
965 1
|
数据采集 存储 人工智能
蚂蚁集团联合上海仁济医院泌尿科发布国内首个临床专科推理数据集:RJUA-QA
详细介绍数据集的构建过程、特点及统计分析,并全面评测了行业和通用大模型在该数据集上的性能,后续团队将持续优化数据集,为人工智能在医疗领域的研究与应用提供有力支持。
蚂蚁集团联合上海仁济医院泌尿科发布国内首个临床专科推理数据集:RJUA-QA
|
存储 NoSQL JavaScript
Linux下快速搭建YApi接口管理平台
目录 一、序言 二、安装Node 1、安装nvm 2、使用兼容的Node版本 二、安装MongoDB 1、下载MongoDB 2、配置MongoDB 三、安装YApi 四、安装PM2管理Node服务 五、登录YApi后台
Linux下快速搭建YApi接口管理平台
|
存储 关系型数据库 程序员
MySQL 的 20+ 条最佳实践
转载:https://code.tutsplus.com/tutorials/top-20-mysql-best-practices–net-7855 数据库操作是当今 Web 应用程序中的主要瓶颈。
1404 0
|
存储 Windows 内存技术
[笔记]Windows核心编程《十五》在应用程序中使用虚拟内存
[笔记]Windows核心编程《十五》在应用程序中使用虚拟内存
153 0