Spiga

发布一个原创小类库:.Net 小型软件自动更新库(SimpAutoUpdater),已附上客户端+包生成工具源码

2011-02-14 23:17 by 木鱼, 5948 visits, 收藏, 编辑

本类库+工具用于快速实现一个简单的自动更新程序,旨在快速简单地为现有的.Net应用程序添加上比较简单的自动更新功能。

在发布应用程序时,我们经常会需要给自己的程序加上自动升级功能。.Net Framework自带的ClickOnce中有自动升级的功能,但是往往不太好用,比如必须用ClickOnce发布,安装的文件夹一个版本一个等等,我们会想要一个比较简单、甚至绿色软件也能使用的自动升级功能,这个自动升级程序就是基于这个目的而制作的。

为了让使用起来更加简单快捷,我对内置的功能进行了大幅度的精简和集成,最简单的情况下只需要你只需要一行代码即可实现自动更新,如下所示: 

  1. FSLib.App.SimpleUpdater.Updater.CheckUpdateSimple(http://ls.com/update.xml);

概述

本类库+工具用于快速实现一个简单的自动更新程序,可以简单地完成小型应用程序的快速更新。

整个工具分成两部分,一部分是供用户使用的类库,一部分是用于生成更新包的工具。

基于 .Net 3.5 开发,原则上最好安装有此版的 .netFramework。特殊情况下,可以仅安装 .Net Framework 2.0SP1,发布的时候附带上 System.Core.dll 即可正常运行。

整个自动升级工作的流程

2d70e14a-d474-4b75-a12a-562d2bce7b74

 更新包生成工具

 

作为一个简单的升级需求,不需要很复杂的设置。

1de73525-2e99-4160-9e62-e71b2694b198

需要填写如下信息:

  1. 应用程序名
  2. 当前的版本(也就是更新后的版本)
  3. 发布地址可选(如果填写了,在更新提示框上会有个链接可以链接到这个网址)
  4. 新程序目录(选择最新版本程序的发布目录)
  5. 升级包路径:选择一个路径用来保存升级包(*.zip),同时自动更新信息 *.xml 也会保存在这个目录下
  6. 更新前执行:在下载完成、即将安装更新前会执行这里选择的程序。这里有点BUG一旦选择了就不能取消,所以请注意下;
  7. 更新后执行:在安装完成后、即将退出前执行的操作。需要注意的BUG同上。通常选择需要运行的主程序。
  8. 执行时间限制:用于限制6中选择的程序的执行时间,超过设置的时间后进程将会被强行结束。
  9. 更新说明:用于提示更新的时候显示的文本消息内容。
  10. 创建:按照填写的信息生成升级包
  11. 打开:打开一个已有的升级信息文件,用于下次更新版本时直接修改信息即可,其它的不需要变化。

发布更新包

更新包应该发布到服务器上。生成的文件有两个,一个是压缩包(*.zip),一个是信息文件(*.xml),两个应该一起发布。这里假定通过网址 http://ls.com/update.xml 能访问到生成的 update.xml 文件。

为应用程序添加自动更新功能

注意:自动升级程序取当前程序文件的版本,是以当前运行的程序集版本作为识别依据的。

首先在VS中为当前的主程序项目添加引用,引用“客户端”中的“SimpleUpdater.exe”。

在VS中,点开“解决方案管理器”中相应项目的“属性”节点,打开 AssemblyInfo.cs 文件,在最下面添加上一行自动更新声明:

这步是必须的,否则请求检查更新时会抛出异常;代码中的网址即上面提到的能访问到xml文件的网址。

 

如果您希望更加简单的使用而不用去加这样的属性,或者您想程序运行的时候自定义,您可以通过下列方式的任何一种方式取代上面的属性声明:

  • 使用 FSLib.App.SimpleUpdater.Updater.CheckUpdateSimple("升级网址")  的重载方法。这个重载方法允许你传入一个升级包的地址;
  • 在检查前手动设置 FSLib.App.SimpleUpdater.Updater.UpdateUrl 属性。这是一个静态属性,也就是说,您并不需要创建 FSLib.App.SimpleUpdater.Updater.UpdateUrl 的对象实例就可以修改它。

 

无论使用哪种方式,请确保在检查更新前,地址已经设置。

到这里,准备工作即告完成,为代码添加上检查更新的操作即可。

 

  1. static class Program
  2. {
  3.     /// <summary>
  4.     /// 应用程序的主入口点。
  5.     /// </summary>
  6.     [STAThread]
  7.     static void Main()
  8.     {
  9.         Application.EnableVisualStyles();
  10.         Application.SetCompatibleTextRenderingDefault(false);
  11.  
  12.         var updater = FSLib.App.SimpleUpdater.Updater.Instance;
  13.  
  14.         //当检查发生错误时,这个事件会触发
  15.         updater.Error += new EventHandler(updater_Error);
  16.         //没有找到更新的事件
  17.         updater.NoUpdatesFound += new EventHandler(updater_NoUpdatesFound);
  18.         //找到更新的事件.但在此实例中,找到更新会自动进行处理,所以这里并不需要操作
  19.         //updater.UpdatesFound += new EventHandler(updater_UpdatesFound);
  20.  
  21.         //开始检查更新-这是最简单的模式.请现在 assemblyInfo.cs 中配置更新地址,参见对应的文件.
  22.         FSLib.App.SimpleUpdater.Updater.CheckUpdateSimple();
  23.  
  24.         /*
  25.          * 如果您希望更加简单的使用而不用去加这样的属性,或者您想程序运行的时候自定义,您可以通过下列方式的任何一种方式取代上面的属性声明:
  26.          * 使用Updater.CheckUpdateSimple 的重载方法。这个重载方法允许你传入一个升级包的地址;
  27.          * 在检查前手动设置 FSLib.App.SimpleUpdater.Updater.UpdateUrl 属性。这是一个静态属性,也就是说,您并不需要创建 FSLib.App.SimpleUpdater.Updater.UpdateUrl 的对象实例就可以修改它。
  28.          */
  29.  
  30.         FSLib.App.SimpleUpdater.Updater.CheckUpdateSimple("升级网址");
  31.        
  32.         Application.Run(new Form1());
  33.     }
  34.  
  35.     static void updater_UpdatesFound(object sender, EventArgs e)
  36.     {
  37.  
  38.     }
  39.  
  40.     static void updater_NoUpdatesFound(object sender, EventArgs e)
  41.     {
  42.         System.Windows.Forms.MessageBox.Show("没有找到更新");
  43.     }
  44.  
  45.     static void updater_Error(object sender, EventArgs e)
  46.     {
  47.         var updater = sender as FSLib.App.SimpleUpdater.Updater;
  48.         System.Windows.Forms.MessageBox.Show(updater.Exception.ToString());
  49.     }
  50. }

结束

详细的代码请参考附带的示例项目。

检查到更新时窗口如下:

28bfbc14-2a3d-49bb-9092-d913a1399d62

这之后的更新操作都是全自动执行的,不需要在主程序中有任何其它操作。

关于开源

当前发布的类库中并未包含源码,因为较多的细节尚未完善。但是有很多同学表示有兴趣,所以这里放出一个源码包,请参见下一节下载。

仅供参考,被误导我可不管 :-)

下载

库直接下载链接:http://www.u-tide.com/fish/Service.asmx/Download/33/28  
源码包直接下载:http://www.u-tide.com/fish/Service.asmx/Download/33/29 

发布页面:http://www.u-tide.com/fish/soft/simple_autoupdater/index.html

简单使用说明:http://www.u-tide.com/fish/soft/simple_autoupdater/usage.html

如果有问题或建议,请回复此日志,到讨论区反馈: http://www.u-tide.com/fish/Discussion.asmx/Index/33

Add your comment

58 条回复

  1. #1楼 小邦      2011-02-14 23:31
    顶。。
     回复 引用 查看   
  2. #2楼 飞越彩虹      2011-02-15 00:08
    好文,收藏了。这位好像就是写字体替换工具的木鱼大啊
     回复 引用 查看   
  3. #3楼[楼主] 木鱼      2011-02-15 00:41
    @飞越彩虹
    嗯?。。。Bingo。。。
     回复 引用 查看   
  4. #4楼 niky      2011-02-15 08:01
    能给出源码么?
     回复 引用 查看   
  5. #5楼 Treenew Lyn      2011-02-15 08:25
    你好,我想知道你是如何解决一下问题的:

    自动更新的“自杀”表现?这个可能涉及到程序被加壳以后,无法“自杀”的现象。
     回复 引用 查看   
  6. #6楼 星释天狼      2011-02-15 08:27
    好文章,能给出源码么?
     回复 引用 查看   
  7. #7楼 Treenew Lyn      2011-02-15 08:39
    我试了一下,不错啊。你是通过显示的方式去结束……
    开源吗?
     回复 引用 查看   
  8. #8楼 咸蛋哥哥      2011-02-15 08:48
    支持,收藏了~~
     回复 引用 查看   
  9. #9楼[楼主] 木鱼      2011-02-15 09:00
    @星释天狼
    @niky
    当前发布的类库中并未包含源码,因为较多的细节尚未完善。在过段时间完善后,将会开源(预计版本1.5.0.0)。

    DLL本身并未经过混淆,有兴趣可以先看看,或发私信给我,我可以单独发给你。
     回复 引用 查看   
  10. #10楼 没有明天      2011-02-15 09:11
    能出源码不?
     回复 引用 查看   
  11. #11楼 电脑混混      2011-02-15 09:22
    Web应用有问题吧,去更新DLL会导致网站程序池回收
     回复 引用 查看   
  12. #12楼[楼主] 木鱼      2011-02-15 09:27
    @没有明天
    当前发布的类库中并未包含源码,因为较多的细节尚未完善。在过段时间完善后,将会开源(预计版本1.5.0.0)。

    DLL本身并未经过混淆,有兴趣可以先看看,或发私信给我,我可以单独发给你。
     回复 引用 查看   
  13. #13楼 游荡的灵魂      2011-02-15 09:27
    http://autoupdatemanager.codeplex.com/

    这贵地宣传一下我的开源自动升级。我很懒就没有写对应文章
     回复 引用 查看   
  14. #14楼[楼主] 木鱼      2011-02-15 09:27
    @电脑混混
    这个是WinForm的,不适用于WebForm,因为更新的时候是用外部的进程来更新的。
     回复 引用 查看   
  15. #15楼 Rainr      2011-02-15 09:34
    不错..支持。
     回复 引用 查看   
  16. #16楼[楼主] 木鱼      2011-02-15 09:34
    @游荡的灵魂
    学习一下! :-)
     回复 引用 查看   
  17. #17楼[楼主] 木鱼      2011-02-15 09:41
    @游荡的灵魂
    兄弟你的自动更新设计的很全面啊 :-)

    我也设计过一个比较全面的自动更新,支持组件可选更新,支持文件级别的自定义更新,只是外部程序集的函数调用等等,还没完善呢,自己先烦了,觉得在大多数情况下完全不需要这样复杂,我们只需要复制新文件覆盖就文件就行了,额外的一点点操作完全可以由外部独立的程序来完成升级操作,所以这个更新类库就出现了……加个Simple是因为在我的源码库里面还有一个完整功能的……未完工自动更新库 - -#
     回复 引用 查看   
  18. #18楼 Crayon      2011-02-15 09:45
    有没有人做过WEB的自动升级,或者安装包,比如部署网站,还有IIS相关的设置。
     回复 引用 查看   
  19. #19楼 Crayon      2011-02-15 09:45
    当然最好是开源的
     回复 引用 查看   
  20. #20楼 电脑混混      2011-02-15 09:51
    @游荡的灵魂
    同楼上的,有没有基于WEB的自动升级解决方案
     回复 引用 查看   
  21. #21楼 深蓝医生      2011-02-15 09:51
    自动更新程序的“自杀”功能可以采用批处理程序完成,即先退出自己,使用批处理程序完成文件拷贝,然后再启动主程序和更新程序。
     回复 引用 查看   
  22. #22楼[楼主] 木鱼      2011-02-15 09:55
    @深蓝医生
    程序本身已经提供了自杀功能,因为实际的更新过程是使用外部程序的,先将升级程序复制到系统临时目录,启动后请求关闭主进程。
     回复 引用 查看   
  23. #23楼[楼主] 木鱼      2011-02-15 09:56
    @Crayon
    当前发布的类库中并未包含源码,因为较多的细节尚未完善。在过段时间完善后,将会开源(预计版本1.5.0.0)。

    DLL本身并未经过混淆,有兴趣可以先看看,或发私信给我,我可以单独发给你。
     回复 引用 查看   
  24. #24楼[楼主] 木鱼      2011-02-15 10:01
    @Crayon
    WEB安装包我记得看到过。但是WEB的升级如果只是网站本身还好办,涉及到服务器配置的话就很复杂了。不知道有没有现成的安装包。

    至于WEB进程池的重启,那是当前请求结束后才重启的,也就是更新覆盖完文件后,这个倒不会太影响。
    当然,大多数网站的进程池权限都不高,想要自动更新来操作服务器,估计有一定的难度。
     回复 引用 查看   
  25. #25楼 longware      2011-02-15 10:33
    +1
     回复 引用 查看   
  26. #26楼 sunriseyuen      2011-02-15 10:45
    能不能做到差异更新,
    如一个系统有3000个文件,现在客户端不知道那些文件是更新了的,能否只下载更新的部分? 假设全部下载是500M,如果只更新的部分可能是2M
     回复 引用 查看   
  27. #27楼[楼主] 木鱼      2011-02-15 11:04
    @sunriseyuen
    这个版本的库是不支持的,因为这个库设计的出发点就是目标小型软件、尽量简化操作、减轻下载负担而设计的。
    差异化更新需要更完善的自动更新功能,这个我的源码库中的项目只写到一半 - -#
     回复 引用 查看   
  28. #28楼 冰河之刃      2011-02-15 11:33
    试一下看看效果。。。
     回复 引用 查看   
  29. #29楼 Crayon      2011-02-15 12:17
    看到某款软件的打包工具,他是delphi写的,基本能实现这样的功能,但是他是产品的一部分,所以想最终还是要自己实现比较好
     回复 引用 查看   
  30. #30楼 iTech      2011-02-15 14:10
    很通用的自动跟新模块!

    不错!支持!
     回复 引用 查看   
  31. #31楼 马战鹏      2011-02-15 14:56
    很不错。。。开源么?
     回复 引用 查看   
  32. #32楼 阳光下的柚子      2011-02-15 15:30
    不错,自己也写过一个,没有你的完善,参考学习一下,谢谢分享
     回复 引用 查看   
  33. #33楼 游荡的灵魂      2011-02-15 16:56
    @木鱼
    我桌面开发转C++了。我的dotnet自动升级应该不会怎么维护了。
     回复 引用 查看   
  34. #34楼 游荡的灵魂      2011-02-15 16:59
    @sunriseyuen
    实际上这个问题在服务器上根据客户端提交的版本重新生成下载列表来实现。。。
    我跟木鱼的解决方案都是,预生成。。
    本来我是有这个打算的,但是现在转C++。所以就这样了
     回复 引用 查看   
  35. #35楼 niky      2011-02-15 21:15
    @木鱼
    好的,其实我最近也做了一个类似的东西(用于在公司的一个项目中代替clickone发布我们的产品),主要是用了圣殿骑士的那个autoupdater组件,但是没有你这个来的系统化,所以想参考一下您的源码
     回复 引用 查看   
  36. #36楼[楼主] 木鱼      2011-02-15 22:29
    @niky
    文中已放出源码,请直接下载 :-)
     回复 引用 查看   
  37. #37楼[楼主] 木鱼      2011-02-15 22:29
    @马战鹏
    @阳光下的柚子
    文中已放出源码,请直接下载 :-)
     回复 引用 查看   
  38. #38楼 xuqiang      2011-02-16 00:06
    下载了,学习了,用起来挺方便的,谢谢
     回复 引用 查看   
  39. #39楼 Kevan      2011-02-16 10:59
    好东西啊@
     回复 引用 查看   
  40. #40楼 xuqiang      2011-02-16 14:15
    事实证明很好用,谢谢!
     回复 引用 查看   
  41. #41楼 johndu      2011-02-17 11:47
    代码写得真不错。
     回复 引用 查看   
  42. #42楼 刺客之家      2011-02-23 22:08
    呵呵。楼主是合肥人?握爪!
     回复 引用 查看   
  43. #43楼 ㄟ荖樹炪厊ㄖ      2011-02-24 20:17
    谢啦,正好要研究这个~~~哈哈 。。
     回复 引用 查看   
  44. #44楼 emil      2011-04-13 13:39
    如果原来的程序时netframework1.1,现在升级到了netframework2.0了 这个怎么自动升级,有考虑吗
     回复 引用 查看   
  45. #45楼[楼主] 木鱼      2011-04-13 13:40
    @emil
    这个没啥好的解决方法..临时我只加了一个最低版本要求,低于此版本的提示用户手动更新.
     回复 引用 查看   
  46. #46楼 emil      2011-04-13 14:16
    楼主在主程序中执行自动更新程序这样行吗?我如果是更新主程序,岂不是挂了。
     回复 引用 查看   
  47. #47楼[楼主] 木鱼      2011-04-13 15:01
    @emil
    不明白啥意思?
     回复 引用 查看   
  48. #48楼 wowoo      2011-07-26 15:53
    楼主的源码用vs2008怎么打不开啊?
     回复 引用 查看   
  49. #49楼[楼主] 木鱼      2011-07-26 15:56
    @wowoo
    源码本身是VS2010的项目格式,VS2008下打开需要对sln文件作出一些修改,关于如何修改可以搜索下,有文章介绍过,用记事本即可以修改。
     回复 引用 查看   
  50. #50楼 刘标才      2011-07-26 22:55
    我之前也写更新的类,请问,你的可以部分更新吗,也就是说跳过版本的更新,问下你那个更新前和更新后执行是运用在什么地方,不太明白这样的需求。
     回复 引用 查看   
  51. #51楼 wangrong55      2011-09-27 09:50
    为什么我用的是都是异常

    我是win7系统,framework 4.0, vs2010, 在用 升级包工具的时候,一点“创建” 就报错 “出现错误:size was 0, but i expected 88”, 后来我在源码里一步步跟,跟到 CreatePackage 函数的第一行就异常: 线程间操作无效:从不是创建控件 “fileAfterExecute” 的线程访问它。后来采用一个笨方法解决了这个线程间操作无效的异常, 在下面 zip.CreateZip(textPackagePath, textNewSoftDir, true, "") 也出错,直接就跳到
    if (curEntry != null)
    { CloseEntry(); }
    最后还是报错:“出现错误:size was 0, but i expected 88”
    我看别人没有说有这种错误的呀,我为什用的这么不顺?
     回复 引用 查看   
  52. #52楼[楼主] 木鱼      2011-09-27 09:52
    引用wangrong55:
    为什么我用的是都是异常

    我是win7系统,framework 4.0, vs2010, 在用 升级包工具的时候,一点“创建” 就报错 “出现错误:size was 0, but i expected 88”, 后来我在源码里一步步跟,跟到 CreatePackage 函数的第一行就异常: 线程间操作无效:从不是创建控件 “fileAfterExecute” 的线程访问它。后来采用一个笨方法解决了这个线程间操作无效的异常, 在下面 zip.CreateZip(textPackagePath, textNewSoftDir, true, "") 也出错,直接就跳到
    i...

    这应该是打包出现的问题。。。压缩包创建的异常。你打包的源文件夹用WinRAR直接压缩为zip试试。
     回复 引用 查看   
  53. #53楼 wangrong55      2011-09-27 10:21
    不好意思,我已经发现问题所在了,不用麻烦各位了。谢谢
     回复 引用 查看   
  54. #54楼 longware      2011-12-19 17:01
    ************** 异常文本 **************
    System.ArgumentOutOfRangeException: “-763900”的值对于“Value”无效。“Value”应介于 'minimum' 和 'maximum' 之间。
    参数名: Value
    在 System.Windows.Forms.ProgressBar.set_Value(Int32 value)
    在 FSLib.App.SimpleUpdater.UpdateControl.RunUpdate.Instance_DownloadProgressChanged(Object sender, RunworkEventArgs e)
    在 FSLib.App.SimpleUpdater.Updater.OnDownloadProgressChanged(RunworkEventArgs e)
    在 FSLib.App.SimpleUpdater.Updater.<BeginUpdate>b__14(Object s, RunworkEventArgs e)
    在 FSLib.App.SimpleUpdater.Wrapper.BackgroundWorker.<.ctor>b__1(Object s)


    我给人用了,更新不起啦,挺郁闷的
     回复 引用 查看   
  55. #55楼[楼主] 木鱼      2011-12-20 10:30
    @longware
    具体的更新地址有吗?方便的话可以提供给我测试一下。
     回复 引用 查看   
  56. #56楼 Henming      2012-01-11 08:36
    很通用的一款更新工作,稍微处理下,就能使用了
    谢谢楼主的好工具
     回复 引用 查看   
  57. #57楼 Henming      2012-01-13 09:31
    为了方便使用,最好加个点击确认更新的委托,方便主窗体进行释放处理
     回复 引用 查看   
  58. #58楼[楼主] 木鱼      2012-01-13 12:23
    @Henming
    谢谢您的建议。
     回复 引用 查看