首先看获取和更新的接口

更新程序Program.cs

  1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.IO;
5 using System.Linq;
6 using System.Threading.Tasks;
7 using System.Windows.Forms;
8
9 namespace Update
10 {
11 static class Program
12 {
13 /// <summary>
14 /// 更新程序启动后复制自身,使用副本进行更新
15 /// -h 不显示界面
16 /// -c 不使用copy更新程序
17 /// -d 更新完成删除自身,通常用在copy的更新程序
18 /// -b 更新下载到备份文件,不替换原文件
19 /// -r 更新完成运行的文件,下一个参数为文件路径
20 /// -k 如果系统正在运行则干掉
21 /// </summary>
22 [STAThread]
23 static void Main(string[] args)
24 {
25 Application.EnableVisualStyles();
26 Application.SetCompatibleTextRenderingDefault(false);
27 Application.ThreadException += Application_ThreadException;
28
29 List<string> lst = args.ToList();
30 if (!lst.Contains("-b") && !lst.Contains("-k"))
31 {
32 //这里判断成程序是否退出
33 if (Process.GetProcessesByName("serviceclient").Length > 0)
34 {
35 MessageBox.Show("服务正在运行,请退出后重试。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
36 return;
37 }
38 }
39
40 if (lst.Contains("-k"))
41 {
42 var ps = Process.GetProcessesByName("serviceclient");
43 if (ps.Length > 0)
44 {
45 ps[0].Kill();
46 }
47 }
48
49 //副本更新程序运行
50 if (!lst.Contains("-c"))//不存在-c 则进行复制运行
51 {
52 string strFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), Guid.NewGuid().ToString() + ".exe");
53 File.Copy(Application.ExecutablePath, strFile);
54 lst.Add("-c");
55 lst.Add("-d");
56 Process.Start(strFile, string.Join(" ", lst));
57 }
58 else
59 {
60 Action actionAfter = null;
61 //将更新文件替换到当前目录
62 if (!lst.Contains("-b"))
63 {
64 actionAfter = () =>
65 {
66 string strUpdatePath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "UpdateCache\\");
67 if (Directory.Exists(strUpdatePath) && Directory.GetFiles(strUpdatePath).Length > 0)
68 {
69 CopyFile(strUpdatePath, System.AppDomain.CurrentDomain.BaseDirectory, strUpdatePath);
70 if (File.Exists(Path.Combine(strUpdatePath, "ver.xml")))
71 File.Copy(Path.Combine(strUpdatePath, "ver.xml"), Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "ver.xml"), true);
72 Directory.Delete(strUpdatePath, true);
73 }
74 };
75 }
76 try
77 {
78 //隐藏运行
79 if (!lst.Contains("-h"))
80 {
81 Application.Run(new FrmUpdate(actionAfter, true));
82 }
83 else
84 {
85 FrmUpdate frm = new FrmUpdate(actionAfter);
86 frm.Down();
87 }
88 }
89 catch (Exception ex)
90 { }
91 //运行更新后的文件
92 if (lst.Contains("-r"))
93 {
94 int index = lst.IndexOf("-r");
95 if (index + 1 < lst.Count)
96 {
97 string strFile = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, lst[index + 1]);
98 if (File.Exists(strFile))
99 {
100 Process.Start(strFile, "-u");
101 }
102 }
103 }
104 //删除自身
105 if (lst.Contains("-d"))
106 {
107 DeleteItself();
108 }
109 }
110 Application.Exit();
111 Process.GetCurrentProcess().Kill();
112 }
113
114 private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
115 {
116 throw new NotImplementedException();
117 }
118 private static void CopyFile(string strSource, string strTo, string strBasePath)
119 {
120 string[] files = Directory.GetFiles(strSource);
121 foreach (var item in files)
122 {
123 string strFileName = Path.GetFileName(item).ToLower();
124
125 if (strFileName == "ver.xml ")
126 {
127 continue;
128 }
129 //如果是版本文件和文件配置xml则跳过,复制完成后再替换这2个文件
130 string strToPath = Path.Combine(strTo, item.Replace(strBasePath, ""));
131 var strdir = Path.GetDirectoryName(strToPath);
132 if (!Directory.Exists(strdir))
133 {
134 Directory.CreateDirectory(strdir);
135 }
136 File.Copy(item, strToPath, true);
137 }
138 string[] dires = Directory.GetDirectories(strSource);
139 foreach (var item in dires)
140 {
141 CopyFile(item, strTo, strBasePath);
142 }
143 }
144
145
146 private static void DeleteItself()
147 {
148 ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/C ping 1.1.1.1 -n 1 -w 1000 > Nul & Del " + Application.ExecutablePath);
149 psi.WindowStyle = ProcessWindowStyle.Hidden;
150 psi.CreateNoWindow = true;
151 Process.Start(psi);
152 }
153 }
154 }

更新程序界面

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml; namespace HW.Print.ServiceClient.Update
{
public partial class FrmUpdate : Form
{
private static string m_strkey = "sdfadsfdsfasdf";//定义一个密钥用以验证权限,不适用ticket
Random r = new Random();
Action m_actionAfter = null;
bool m_blnShow = false;
public FrmUpdate(Action actionAfter, bool blnShow = false)
{
m_blnShow = blnShow;
m_actionAfter = actionAfter;
InitializeComponent();
} private void Form1_VisibleChanged(object sender, EventArgs e)
{
if (Visible)
{
var rect = Screen.PrimaryScreen.WorkingArea;
this.Location = new Point(rect.Right - this.Width, rect.Bottom - this.Height);
}
} private void FrmUpdate_Load(object sender, EventArgs e)
{
Thread th = new Thread(() =>
{
Down();
this.BeginInvoke(new MethodInvoker(delegate ()
{
this.Close();
}));
});
th.IsBackground = true;
th.Start();
}
private string CheckIsXP(string strUrl)
{
bool blnXp = false;
if (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 1)
{
blnXp = true;
}
if (blnXp && strUrl.StartsWith("https"))
{
strUrl = "http" + strUrl.Substring(5);
}
return strUrl;
} private void SetProcess(string strTitle, int? value, int? maxValue = null)
{
this.lblMsg.BeginInvoke(new MethodInvoker(delegate ()
{
if (maxValue.HasValue)
{
this.progressBar1.Maximum = maxValue.Value;
}
if (value.HasValue)
{
this.progressBar1.Value = value.Value;
}
if (!string.IsNullOrEmpty(strTitle))
{
this.lblMsg.Text = strTitle;
}
lblValue.Text = this.progressBar1.Value + "/" + this.progressBar1.Maximum;
}));
} public void Down()
{
if (m_blnShow)
SetProcess("正在检查版本", null);
try
{
//先清理掉旧文件
try
{
if (Directory.Exists(System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache"))
{
Directory.Delete(System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache", true);
}
}
catch { }
if (!File.Exists(System.AppDomain.CurrentDomain.BaseDirectory + "setting.dat"))
{
Log.WriteLog("配置文件setting.dat不存在!");
return;
}
string strFileUrl = File.ReadAllText(System.AppDomain.CurrentDomain.BaseDirectory + "setting.dat"); strFileUrl = CheckIsXP(strFileUrl);
//获取列表文件
string json = HttpGet(strFileUrl.Trim('/') + "/getUpdaterList?key=" + Encrypt(m_strkey), Encoding.UTF8);
ResponseMessage rm = fastJSON.JSON.ToObject<ResponseMessage>(json);
if (rm == null)
{
Log.WriteLog("获取更新文件错误");
return;
}
if (!rm.Result)
{
Log.WriteLog("获取更新文件错误:" + rm.ErrorMessage);
return;
}
//云列表
Dictionary<string, DateTime> lstNewFiles = new Dictionary<string, DateTime>();
XmlDocument doc = new XmlDocument();
doc.LoadXml(rm.KeyValue);
var documentElement = doc.DocumentElement;
var nodes = documentElement.SelectNodes("//files/file");
foreach (XmlNode item in nodes)
{
lstNewFiles[item.InnerText] = DateTime.Parse(item.Attributes["time"].Value);
} List<string> lstUpdateFile = new List<string>();
string locationXml = System.AppDomain.CurrentDomain.BaseDirectory + "ver.xml";
if (!File.Exists(locationXml))
{
lstUpdateFile = lstNewFiles.Keys.ToList();
}
else
{
XmlDocument docLocation = new XmlDocument();
docLocation.Load(locationXml);
var documentElementLocation = docLocation.DocumentElement;
var nodesLocation = documentElementLocation.SelectNodes("//files/file");
foreach (XmlNode item in nodesLocation)
{
if (!lstNewFiles.ContainsKey(item.InnerText))
{
lstUpdateFile.Add(item.InnerText);
}
else if (lstNewFiles[item.InnerText] < DateTime.Parse(item.Attributes["time"].Value))
{
lstUpdateFile.Add(item.InnerText);
}
}
}
if (lstUpdateFile.Count > 0)
{
string strRootPath = System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache";
if (!System.IO.Directory.Exists(strRootPath))
{
System.IO.Directory.CreateDirectory(strRootPath);
}
SetProcess("", null, lstUpdateFile.Count);
for (int i = 0; i < lstUpdateFile.Count; i++)
{
if (m_blnShow)
SetProcess("正在下载:" + lstUpdateFile[i], i + 1); string filejson = HttpGet(strFileUrl.Trim('/') + "/downloadUpdaterFile?key=" + Encrypt(m_strkey) + "&file=" + System.Web.HttpUtility.UrlEncode(lstUpdateFile[i]), Encoding.UTF8);
ResponseMessage filerm = fastJSON.JSON.ToObject<ResponseMessage>(filejson);
if (rm == null)
{
Log.WriteLog("下载更新文件错误");
return;
}
if (!rm.Result)
{
Log.WriteLog("下载更新文件错误:" + rm.ErrorMessage);
return;
} string saveFile = Path.Combine(strRootPath, lstUpdateFile[i]);
if (!Directory.Exists(Path.GetDirectoryName(saveFile)))
{
System.IO.Directory.CreateDirectory(Path.GetDirectoryName(saveFile));
}
string strbase64 = filerm.KeyValue;
MemoryStream stream = new MemoryStream(Convert.FromBase64String(strbase64));
FileStream fs = new FileStream(strRootPath + "\\" + lstUpdateFile[i], FileMode.OpenOrCreate, FileAccess.Write);
byte[] b = stream.ToArray();
fs.Write(b, 0, b.Length);
fs.Close(); } doc.Save(System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache//ver.xml"); if (m_actionAfter != null)
{
if (m_blnShow)
SetProcess("替换文件", null);
m_actionAfter();
} if (m_blnShow)
SetProcess("更新完成。", null);
}
else
{
if (m_blnShow)
SetProcess("没有需要更新的文件。", null);
}
}
catch (Exception ex)
{
if (m_blnShow)
SetProcess("获取更新列表失败:" + ex.Message, null);
Log.WriteLog(ex.ToString());
}
finally
{
if (m_blnShow)
Thread.Sleep(3000);
}
} private static string encryptKey = "111222333444555666"; //默认密钥向量
private static byte[] Keys = { 0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79, 0x53, 0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F };
/// <summary>
/// 加密
/// </summary>
/// <param name="encryptString"></param>
/// <returns></returns>
public static string Encrypt(string encryptString)
{
if (string.IsNullOrEmpty(encryptString))
return string.Empty;
RijndaelManaged rijndaelProvider = new RijndaelManaged();
rijndaelProvider.Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32));
rijndaelProvider.IV = Keys;
ICryptoTransform rijndaelEncrypt = rijndaelProvider.CreateEncryptor(); byte[] inputData = Encoding.UTF8.GetBytes(encryptString);
byte[] encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length); return System.Web.HttpUtility.UrlEncode(Convert.ToBase64String(encryptedData));
}
public static string HttpGet(string url, Encoding encodeing, Hashtable headht = null)
{
HttpWebRequest request; //如果是发送HTTPS请求
//if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
//{
//ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
request = WebRequest.Create(url) as HttpWebRequest;
request.ServicePoint.Expect100Continue = false;
request.ProtocolVersion = HttpVersion.Version11;
request.KeepAlive = true;
//}
//else
//{
// request = WebRequest.Create(url) as HttpWebRequest;
//}
request.Method = "GET";
//request.ContentType = "application/x-www-form-urlencoded";
request.Accept = "*/*";
request.Timeout = 30000;
request.AllowAutoRedirect = false;
WebResponse response = null;
string responseStr = null;
if (headht != null)
{
foreach (DictionaryEntry item in headht)
{
request.Headers.Add(item.Key.ToString(), item.Value.ToString());
}
} try
{
response = request.GetResponse(); if (response != null)
{
StreamReader reader = new StreamReader(response.GetResponseStream(), encodeing);
responseStr = reader.ReadToEnd();
reader.Close();
}
}
catch (Exception)
{
throw;
}
return responseStr;
}
}
}

定义服务端接口,你可以用任意接口都行,我这里用webapi

获取文件列表

 1 [HttpGet]
2 public HttpResponseMessage GetUpdaterList(string key)
3 {
4 HttpResult httpResult = new HttpResult();
5 if (!CheckKey(key))
6 {
7 httpResult.KeyValue = "";
8 httpResult.Result = false;
9 httpResult.ErrorMessage = "无权限访问";
10 }
11 else
12 {
13 //获取printupdate目录下update.exe的修改日期返回
14 string path = Path.Combine(HttpRuntime.AppDomainAppPath, "printupdate");
15 StringBuilder strXml = new StringBuilder();
16 strXml.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
17 strXml.AppendLine("<files>");
18 if (Directory.Exists(path))
19 {
20 string[] fs = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
21 var _p = path.ToLower().Trim().Length + 1;
22 foreach (var item in fs)
23 {
24 var dt = File.GetLastAccessTime(item);
25 strXml.AppendLine("<file time=\"" + dt.ToString("yyyy-MM-dd HH:mm:ss") + "\">" + item.Substring(_p) + "</file>");
26 }
27 }
28 strXml.AppendLine("</files>");
29
30 httpResult.KeyValue = strXml.ToString();
31 httpResult.Result = true;
32 httpResult.ErrorMessage = "";
33 }
34 return new HttpResponseMessage { Content = new StringContent(httpResult.ToJson(), Encoding.GetEncoding("UTF-8"), "application/json") };
35 }

下载文件,我这里将文件序列号为base64字符串了,你可以直接返回文件流也行

 1 [HttpGet]
2 public HttpResponseMessage DownloadUpdaterFile(string key, string file)
3 {
4 HttpResult httpResult = new HttpResult();
5 if (!CheckKey(key))
6 {
7 httpResult.KeyValue = "";
8 httpResult.Result = false;
9 httpResult.ErrorMessage = "无权限访问";
10 }
11 else
12 {
13 string path = Path.Combine(HttpRuntime.AppDomainAppPath + "printupdate", file);
14 if (!File.Exists(path))
15 {
16 httpResult.KeyValue = "";
17 httpResult.Result = false;
18 httpResult.ErrorMessage = "文件不存在";
19 }
20 else
21 {
22 httpResult = ConvertToBase64Type(path);
23 }
24 }
25 return new HttpResponseMessage { Content = new StringContent(httpResult.ToJson(), Encoding.GetEncoding("UTF-8"), "application/json") };
26
27 }

1   HttpResult ConvertToBase64Type(string fileName)
2 {
3 HttpResult httpResult = new HttpResult();
4 var byts = File.ReadAllBytes(fileName);
5 httpResult.KeyValue = Convert.ToBase64String(byts);
6 return httpResult;
7 }

1  bool CheckKey(string key)
2 {
3 return key == Encryption.Encrypt(m_strkey);
4 }

 1  private static string encryptKey = "111222333444";
2
3 //默认密钥向量
4 private static byte[] Keys = { 0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79, 0x53, 0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F };
5 /// <summary>
6 /// 加密
7 /// </summary>
8 /// <param name="encryptString"></param>
9 /// <returns></returns>
10 public static string Encrypt(string encryptString)
11 {
12 if (string.IsNullOrEmpty(encryptString))
13 return string.Empty;
14 RijndaelManaged rijndaelProvider = new RijndaelManaged();
15 rijndaelProvider.Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32));
16 rijndaelProvider.IV = Keys;
17 ICryptoTransform rijndaelEncrypt = rijndaelProvider.CreateEncryptor();
18
19 byte[] inputData = Encoding.UTF8.GetBytes(encryptString);
20 byte[] encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length);
21
22 return Convert.ToBase64String(encryptedData);
23 }

需要注意的地方:

1、我这里用到了json,那么不能直接饮用json的dll文件,会出现更新时候占用的问题,可以使用fastjson的开源代码,放进来解决,你可以直接使用xml格式的返回内容,这样就不需要json了,这样更方便

2、如果你的下载接口是返回的文件流,那么你更新程序里面直接接收流保存文件就行了

3、Program.cs里面,停止服务的功能,其实是可以通过传递参数的形式来停止,我这里写死了,你们根据自己需求修改

效果

你可以根据自己的需求,修改下界面效果,这是最简单的示例界面而已。

c# 自动更新程序的更多相关文章

  1. C#之tcp自动更新程序

    .NETTCP自动更新程序有如下几步骤: 第一步:服务端开启监听 ServiceHost host; private void button1_Click(object sender, EventAr ...

  2. ASP.NET网站版本自动更新程序及代码[转]

    1.自动更新程序主要负责从服务器中获取相应的更新文件,并且把这些文件下载到本地,替换现有的文件.达到修复Bug,更新功能的目的.用户手工点击更新按钮启动更新程序.已测试.2.环境VS2008,采用C# ...

  3. WPF自动更新程序

    WPF AutoUpdater 描述: WPF+MVVM实现的自动更新程序 支持更新包文件验证(比较文件MD5码) 支持区分x86与x64程序的更新 支持更新程序的版本号 支持执行更新策略 截图: 使 ...

  4. winform自动更新程序实现

    一.问题背景 本地程序在实际项目使用过程中,因为可以操作电脑本地的一些信息,并且对于串口.OPC.并口等数据可以方便的进行收发,虽然现在软件行业看着动不动都是互联网啊啥的,大有Web服务就是高大上的感 ...

  5. C# WINFORM的自动更新程序

    自动更新程序AutoUpdate.exe https://git.oschina.net/victor596jm/AutoUpdate.git 1.获取源码 http://git.oschina.ne ...

  6. C#.Net版本自动更新程序及3种策略实现

    C#.Net版本自动更新程序及3种策略实现 C/S程序是基于客户端和服务器的,在客户机编译新版本后将文件发布在更新服务器上,然后建立一个XML文件,该文件列举最新程序文件的版本号及最后修改日期.如程序 ...

  7. winform 通用自动更新程序

    通用自动更新程序 主要功能: 1. 可用于 C/S 程序的更新,集成到宿主主程序非常简单和配置非常简单,或不集成到主程序独立运行. 2. 支持 HTTP.FTP.WebService等多种更新下载方式 ...

  8. .Net自动更新程序GeneralUpdate,适用于wpf,winfrom,控制台应用

    什么是GeneralUpdate: GeneralUpdate是基于.net framwork4.5.2开发的一款(c/s应用)自动升级程序. 第一个版本叫Autoupdate(原博客: WPF自动更 ...

  9. android自动更新程序,安装完以后就什么都没有了,没有出现安装成功的界面的问题

    转载自: http://blog.csdn.net/lovexieyuan520/article/details/9250099 在android软件开发中,总是需要更新版本,所以当有新版本开发的时候 ...

  10. Winfrom强大的自动更新程序

    推荐一:.Net 小型软件自动更新库(SimpAutoUpdater) http://www.fishlee.net/soft/simple_autoupdater/usage.html 下载地址:h ...

随机推荐

  1. Redis 客户端 Jedis、lettuce 和 Redisson 对比

    Redis 支持多种语言的客户端,下面列举了部分 Redis 支持的客户端语言,大家可以通过官网查看 Redis 支持的客户端详情. C语言 C++ C# Java Python Node.js PH ...

  2. 多测师讲解接口自动化测试 _requests_高级讲师肖sir

    rep=requests.post 错误方法: 1.在代理中---把高级中----代理-----去除勾选,调用失败

  3. day64 Pyhton 框架Django 07

    day67 内容回顾 视图 1. CBV 定义 from django.views import View class Addpub(View): def get(self,request): sel ...

  4. Linux文件系统和管理-2文件操作命令(下)

    移动和重命名文件 mv 命令可以实现文件或目录的移动和改名 剪切的效果 同一分区移动数据,速度很快:数据位置没有变化 不同分区移动数据,速度相对慢:数据位置发生了变化 格式 和cp基本一样 mv [O ...

  5. day73:drf:drf视图相关类&路由Routers&创建虚拟环境

    目录 1.APIView 2.GenericAPIView:通用视图类 3.5个视图扩展类:ListModelMixin,CreateModelMixin,RetrieveModelMixin,Upd ...

  6. 5年Android程序员面试字节跳动两轮后被完虐,请查收给你的面试指南

    大家应该看过很多分享面试成功的经验,但根据幸存者偏差的理论,也许多看看别人面试失败在哪里,对自己才更有帮助. 最近跟一个朋友聊天,他准备了几个月,刚刚参加完字节跳动面试,第二面结束后,嗯,挂了- 所以 ...

  7. 字体图标:Font Awesome

    小图标 Font Awesome Font Awesome 字体为您提供可缩放矢量图标,它可以被定制大小.颜色.阴影以及任何可以用 CSS 的样式,是一款惊艳的字体图标! 可以前往官网进行学习 Fon ...

  8. F2. Same Sum Blocks (Hard) 解析(思維、前綴和、貪心)

    Codeforce 1141 F2. Same Sum Blocks (Hard) 解析(思維.前綴和.貪心) 今天我們來看看CF1141F2(Hard) 題目連結 題目 給你一個數列\(a\),要你 ...

  9. Docker学习—DockerFile

    前言: 上一篇文章简单使用了docker 拉取镜像.启动容器.编译镜像:其中编译镜像时,使用到了Dockerfile,那么接下来我们就详细的来说说Dockerfile DockerFile是什么: D ...

  10. python使用redis缓存数据库

    Redis 关注公众号"轻松学编程"了解更多. Windows下直接解压可用,链接:https://pan.baidu.com/s/1rD4ujoN7h96TtHSu3sN_hA ...