ClickOnce DIY全自动更新下载升级的自我实现

news/2023/12/1 5:02:16
 
SmartClient 概念近来比较热,但在微软提出这个名词以前已经有大量的软件在这么做了,一方面是简化客户端的部署,一方面是提供自动升级的功能;对于传统的 WinForm 应用来讲,确实是可以降低维护成本的一个不错的解决方案;
  微软在推出 SmartClient 概念时,推出了相关的 updater Application Block ,做的也蛮不错,但作者前段还是根据软件特性自己写了一个很简单的实现,大家也大概能了解一下原理:
笔者的简化版自动升级管理器只需要四步走:
1. 一个负责查找和下载新版本的本地类
2.
本地配置文件中(或在代码中硬编码?不太好吧),指向更新服务器的 URL
3.
服务器上一个标识版本号和新文件 URL 的配置文件
4.
调用示例
1. 版本管理类
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Net;
using System.IO;
using System.Windows.Forms;
namespace Survey
{
    class VersionAgent
    {
        public static bool CheckNetwork()
        {
            HttpWebRequest request;
            try
            {
                request = (HttpWebRequest)WebRequest.Create(Pub.GetSetting("UpdateUrl") );//
从本地配置文件获取的网络中配置文件的 URL
                request.Proxy = WebProxy.GetDefaultProxy();
                request.GetResponse();//
如果可以获得响应,说明网络没问题
            }
            catch (Exception e)
            {
                Pub.logError(e);
                return false;
            }
            return true;
        }
 
        public static bool CheckUpdate()
        {
            XmlDocument doc = loadXMLDocument(Pub.GetSetting("UpdateUrl"));
            Sys.UpdateUrl = GetValue(doc, "DownloadURL").Trim();//
将来会用这个 URL 自动下载
            Sys.UpdatePage = GetValue(doc, "DownloadPage").Trim();//
如自动下载失败,会提供到这个页面手工下载
            string warningRate = GetValue(doc, "WarningRate").Trim();
            float.TryParse(warningRate,out Sys.WarningRate);
            string NetVersion = GetValue(doc, "Version").Trim();
Version LocalVersion=System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
            return new Version(NetVersion).CompareTo(new Version(LocalVersion))>0;// 大于 0 说明有新版本发布
        }//
这个方法是载入网络配置文件,读取一些不想放在本地的配置参数,以及比较本地和网络版本号
        public static bool GoUpdate()
        {
          return DownLoadFile(Sys.UpdateFile,Sys.UpdateUrl);
         
        }
        public static string GetValue(XmlDocument doc, string Key)
        {
            string Value;
            try
            {
                XmlElement elem = (XmlElement)doc.SelectSingleNode(@"/config/app/" + Key);//
读取配置文件可自行定义
                Value = elem == null ? "" : elem.GetAttribute("value");
            }
            catch
            {
                Value = "";
            }
            return Value;
        }
        public static XmlDocument loadXMLDocument(string FileNameOrUrl)
        {
            XmlDocument doc = null;
            try
            {
                doc = new XmlDocument();
                doc.Load( FileNameOrUrl);
            }
            catch (Exception e)
            {
                System.Windows.Forms.MessageBox.Show(e.Message);
                Pub.logError(e);
                doc = null;
            }
            return doc;
        }
 
        public static bool DownLoadFile(string FileName, string Url)
        {
            bool Value = false;
            WebResponse response = null;
            Stream stream = null;
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
                response = request.GetResponse();
                stream = response.GetResponseStream();
                if (!response.ContentType.ToLower().StartsWith("text/"))
                {
                    Value = SaveBinaryFile(response, FileName);
                }
            }
            catch (Exception e)
            {
               // System.Windows.Forms.MessageBox.Show(e.Message);
                Pub.logError(e);
            }
            return Value;
        }
 
        private static bool SaveBinaryFile(WebResponse response, string FileName)
        {
            bool Value = true;
            byte[] buffer = new byte[1024];
            try
            {
                if (File.Exists(FileName))
                    File.Delete(FileName);
                Stream outStream = System.IO.File.Create(FileName);
                Stream inStream = response.GetResponseStream();
                int l;
                do
                {
                    l = inStream.Read(buffer, 0, buffer.Length);
                    if (l > 0)
                        outStream.Write(buffer, 0, l);
                }
                while (l > 0);
                outStream.Close();
                inStream.Close();
            }
            catch (Exception e)
            {
                System.Windows.Forms.MessageBox.Show(e.Message);
                Pub.logError(e);
                Value = false;
            }
            return Value;
        }
    }
}
2. 本地配置文件可能如:

 
   
 
3. 网络配置文件可能如:

 
   
   
   
   
  
 
4. 调用示例
在认为合适的时机(比如说应用程序启动时),启动一个后台线程去工作:
            Thread thread = new Thread(new ThreadStart(threadMethodUpdate));
            thread.Start();
 
        private void threadMethodUpdate()
        {

            if (VersionAgent.CheckNetwork())//
网络状况正常
            {
                if (VersionAgent.CheckUpdate())//
检查更新并获取网络参数
                {
                    if (VersionAgent.GoUpdate())//
获取新版本(由于我的软件很小,所以在不提示用户的情况就进行了新版下载,如认为不妥,可通过 MessageBox 提示一下)
                    {
                        MessageBox.Show("
检测到产品的更新版本 , 即将开始自动更新! ", " 版本升级 ", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        System.Diagnostics.Process.Start(Sys.UpdateFile);
                        System.Environment.Exit(0);
                    }
                    else
                    {
                        MessageBox.Show("
系统检测到更新版本,但自动下载失败,点击确定进行手动下载 ", " 版本升级 ", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        System.Diagnostics.Process.Start(Sys.UpdatePage);
                        System.Environment.Exit(0);
                    }
                }
            }
            else//
也可以什么也不提示
                MessageBox.Show("
无法连接到服务器进行自动升级! /n 请检查网络连接 " + Pub.GetSetting("UpdateUrl"), " 网络异常 ", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
 
 



http://www.niftyadmin.cn/n/3656718.html

相关文章

基于qemu-riscv从0开始构建嵌入式linux系统ch19. 交叉编译sudo

基于qemu-riscv从0开始构建嵌入式linux系统ch19. 交叉编译sudo sudo sudo源码可以在sudo网站上下载:https://www.sudo.ws/download.html。sudo可以说在linux系统上用户使用率还是比较高的命令,安装sudo之后我们可以在管理员用户上使用系统,…

C#开发可穿透代理服务器的WinForm应用

企业上网一般都是通过网关服务器,部分非自动的代理服务器需要手工设置(就像IE需要在连接-局域网设置-代理器中的那样),前段为企业开发了一个需要远程访问HTTP服务器的应用,发现在手动代理的网络环境下,会在运行时WebRequest试图通…

.NET的两种反射方式

.net反射之一:.NET技术与Java可以说是系出同门, 各领风骚,在framework的各层次各方面都有神似之处,但为了不过于形似,就常常改换名头,此地无银地力图证明我们这是百分百原创啊!比如说较常用的ja…

Tomcat类加载机制

说到本篇的tomcat类加载机制,不得不说翻译学习tomcat的初衷。 之前实习的时候学习javaMelody的源码,但是它是一个Maven的项目,与我们自己的web项目整合后无法直接断点调试。后来同事指导,说是直接把java类复制到src下就可以了。很…

基于qemu-riscv从0开始构建嵌入式linux系统ch20. 交叉编译screen、tree、cu

基于qemu-riscv从0开始构建嵌入式linux系统ch20. 交叉编译screen、tree、cu screen screen源码可以在gnu网站上下载:https://ftp.gnu.org/gnu/screen/。screen是个人非常喜欢的终端管理工具,在没有图形界面的系统中,使用screen可以实现多终…

Case Foxmail of:战略联盟还是败走麦城?

FoxmailⅢ WPSWindows OEOUTLOOK ExpressDelphiFoxmailFreeware12003721YahooIT 1996Foxmail2000FoxmailCase 1腾讯谁人?当今中国IM(Instant Message)乱世的三国枭雄,微软兵强马壮粮草丰足却也相持不下无力吞并,I…

基于qemu-riscv从0开始构建嵌入式linux系统ch21. 实时操作系统FreeRTOS移植RISCV-S模式

基于qemu-riscv从0开始构建嵌入式linux系统ch21. 实时操作系统FreeRTOS移植RISCV-S模式 FreeRTOS FreeRTOS在嵌入式行业内是非常出名了,这么多节过去了,我们不能忘记除了7个core上运行的linux系统外,我们还有个trusted_domain,今…

涅槃的火鸟-Pascal前世今生之一(开天辟地-Algol新元初创)

Algol(ALGOrithmic Language)ALGOL 58ALGOL 60ALGOL 68AlgolFORTRANCOBOLAlgolAlgolCall By NameIf - then elseAlgolALGOLALGOLALGOL 在六十年代后期, 几个演化改进的语言借鉴了Algol的得失而相继出现,芸芸之众间就有将Algol的精髓思想发扬光大&…

基于qemu-riscv从0开始构建嵌入式linux系统ch22. 编译器与C/C++标准库

基于qemu-riscv从0开始构建嵌入式linux系统ch22. 编译器与C/C标准库 更换编译器 项目进行到后期我才发现,我们之前下载的二进制的编译器虽然方便使用,但是很多适合debug问题难免需要去编译器代的libc库里阅读具体实现,鉴于我们是学习性质的…

涅槃的火鸟-Pascal前世今生之二(风生水起-Pascal承接衣钵)

PascalAlgol1968Algol(the Swiss Federal Institute of Technology ETH-Zurich)-(Niklaus Wirth)AlgolAlgol1970CDC 6000 1971 WirthAlgolCaseAlgol CobolPL/1FortranAlgol17(Blaise Pascal) Wirth教授可能也没想到,这个本计划只被用于大学教授数据结构的小资…

动态hash思想方法

文将介绍三种动态hash方法。 散列是一个非常有用的、非常基础的数据结构,在数据的查找方面尤其重要,应用的非常广泛。然而,任何事物都有两面性,散列也存在缺点,即数据的局部集中性会使散列的性能急剧下降,…

上周五的MS一道面试题

题目要求:写一个返回两个任意字串中最大公共串的函数,即abcdef 和 qcfbcc 返回值为bc语言不限我的思路:1.确定一个串为长串,另一个串为短串,在长串中找短串(长串中最长的公串可能性就是短串本身)2.顺序确定短串中的每个…

基于qemu-riscv从0开始构建嵌入式linux系统ch23. linux FB应用——Qt库移植

基于qemu-riscv从0开始构建嵌入式linux系统ch23. linux FB应用——Qt库移植 Qt 应该是做嵌入式开发和做linux应用开发的朋友都很熟悉的东西,Qt是一套C的开发库,主要被应用与GUI开发中,既然我们之前已经成功启用了qemu虚拟的显示设备驱动&am…

diamondlost-别了,我心中的Borland!

技术和产品行不行,要看开发者是在流失还是激增,关于Delphi,不敢说拥护者是在增加,而是像我这样一个个伤心地离去,记得当年用Delphi写就"代码千行几,又思量"时的激情,然后那种感觉已经与我渐行渐远,是我的朝秦暮楚贪新厌旧?还是Delphi的日薄西山豪情气尽,这不是我应该…

基于qemu-riscv从0开始构建嵌入式linux系统ch24. qemu网卡/linux内核网络配置

基于qemu-riscv从0开始构建嵌入式linux系统ch24. qemu网卡/linux内核网络配置 virtio-net-device 本节我们给系统添加网络相关的配置,和之前一样virtio-mmio还提供了网络设备的注册,这里我们选择添加qemu支持的最简单的user模式网络,其他博…

Java动态代理的实现

概念 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个…
最新文章