c#更新工具,wpf开发,所有windows桌面程序均可使用,基于.net 4.0,最低支持windos xp系统
更新工具优点
- 使用简单
- 批量更新
- 跨版本更新
- 数据备份
- 手动还原数据
- 体积小
程序更新使用效果
使用简单
只需添加两个类,以及三个路径的指定,就可以从任何地方下载更新包,并解压到主程序目录中,自动启动
批量更新
不管你从后台拿到了多少个升级包,都能一次性完成升级(以下升级包为本地测试数据)
手动还原数据至上一版本
体积小
依赖少,占用空间少
如何使用
添加类ClientParameter.cs
public class ClientParameter
{
/// <summary>
/// 1:MainApp 2:UpdateApp
/// </summary>
public int AppType { get; set; } = 1;
/// <summary>
/// 启动程序名称(可以加上相对路径)
/// </summary>
public string AppName { get; set; }
/// <summary>
/// 下载的内容放到哪里
/// </summary>
public string DownLoadPath { get; set; }
/// <summary>
/// 解压的内容放到哪里
/// </summary>
public string UnZipPath { get; set; }
/// <summary>
/// 备份地址
/// </summary>
public string BackUpPath { get; set; }
/// <summary>
/// 客户端版本当前
/// </summary>
public string ClientVersion { get; set; }
/// <summary>
/// 日志访问地址
/// </summary>
public string UpdateLogUrl { get; set; }
/// <summary>
/// 是否修改目标版本(通过修改version.ini的方式统一控制版本)
/// </summary>
public bool IsUpdateVersion { get; set; } = true;
/// <summary>
/// 是否是还原版本
/// </summary>
public bool IsRestore { get; set; } = false;
/// <summary>
/// 多版本更新
/// </summary>
public List<UpdateVersion> UpdateVersions { get; set; }
}
public class UpdateVersion
{
public UpdateVersion(string version, string url, string name, bool isUpdate = true)
{
Version = version;
Url = url;
Name = name;
IsUpdate = isUpdate;
}
public UpdateVersion(string version, string url, bool isUpdate = true)
{
Version = version;
Url = url;
IsUpdate = isUpdate;
}
/// <summary>
/// 更新的包名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 更新的版本
/// </summary>
public string Version { get; set; }
/// <summary>
/// 包地址
/// </summary>
public string Url { get; set; }
/// <summary>
/// 是否更新
/// </summary>
public bool IsUpdate { get; set; }
}
添加类UpdateUtil.cs
public static class UpdateUtil
{
#region API函数声明-必须放在类中
[DllImport("kernel32")]//返回0表示失败,非0为成功
private static extern long WritePrivateProfileString(string section, string key,
string val, string filePath);
[DllImport("kernel32")]//返回取得字符串缓冲区的长度
private static extern long GetPrivateProfileString(string section, string key,
string def, StringBuilder retVal, int size, string filePath);
#endregion
public static string Serialize(object obj)
{
if (obj == null) return string.Empty;
var json = JsonConvert.SerializeObject(obj);
var bytes = Encoding.Default.GetBytes(json);
var base64str = Convert.ToBase64String(bytes);
return base64str;
}
public static T Deserialize<T>(string str)
{
var obj = default(T);
if (string.IsNullOrEmpty(str)) return obj;
try
{
byte[] bytes = Convert.FromBase64String(str);
var json = Encoding.Default.GetString(bytes);
var result = JsonConvert.DeserializeObject<T>(json);
return result;
}
catch (Exception)
{
return default;
}
}
#region 写Ini文件
/// <summary>
/// 将内容写入指定的ini文件中
/// </summary>
/// <param name="Section">ini文件中的节名</param>
/// <param name="Key">ini文件中的键</param>
/// <param name="Value">要写入该键所对应的值</param>
/// <param name="iniFilePath">ini文件路径</param>
/// <returns></returns>
public static bool Write(string Section, string Key, string Value, string iniFilePath)
{
if (!File.Exists(iniFilePath))
{
try
{
FileStream stream = File.Open(iniFilePath, FileMode.Create, FileAccess.Write);
//stream.Seek(0, SeekOrigin.Begin);
//stream.SetLength(0); //清空txt文件
stream.Dispose();
stream.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
if (File.Exists(iniFilePath))
{
long OpStation = WritePrivateProfileString(Section, Key, Value, iniFilePath);
if (OpStation == 0)
{
return false;
}
else
{
return true;
}
}
else
{
return false;
}
}
#endregion
/// <summary>
/// 读取ini文件内容的方法
/// </summary>
/// <param name="Section">ini文件的节名</param>
/// <param name="Key">ini文件对应节下的健名</param>
/// <param name="NoText">ini文件对应节对应健下无内容时返回的值</param>
/// <param name="iniFilePath">该ini文件的路径</param>
/// <returns></returns>
public static string Read(string Section, string Key, string NoText, string iniFilePath)
{
if (File.Exists(iniFilePath))
{
StringBuilder temp = new StringBuilder(1024);
GetPrivateProfileString(Section, Key, NoText, temp, 1024, iniFilePath);
return temp.ToString();
}
else
{
return null;
}
}
}
生成的程序项目结构如下
主程序生成至current文件夹下,更新程序生成至update文件夹下
执行更新处添加如下代码
ClientParameter clientParameter = new ClientParameter {
AppName = appName,
BackUpPath = backUpPath,
DownLoadPath = downLoadPath,//下载包临时存放位置 可默认
UnZipPath = unZipPath,//解压文件存放位置,可默认
UpdateLogUrl = "",//更新成功后会自动跳转至该路径 为空则不跳转
UpdateVersions = new List<UpdateVersion> {
new UpdateVersion("1.0.2","http://127.0.0.1:5000/v3.23.12_202312051713.zip"),
new UpdateVersion("1.0.3","http://127.0.0.1:5000/Avalonia-11.0.0-preview4.zip"),
//new UpdateVersion("1.0.4","http://127.0.0.1:5000/Dragablz-master.zip"),
new UpdateVersion("1.0.5","http://127.0.0.1:5000/EChartsSDK-master.zip"),
new UpdateVersion("1.0.6","http://127.0.0.1:5000/EChartsNet-master.zip"),
//new UpdateVersion("1.0.7","http://127.0.0.1:5000/HandyControl-master.zip"),
new UpdateVersion("1.0.8","http://127.0.0.1:5000/Live-Charts-master.zip"),
}
};
string arg = UpdateUtil.Serialize(clientParameter);
var path = directInfo.Parent.FullName + @"\download\Cloud.Update.exe";
if (File.Exists(path))
{
Process.Start(path, arg);
Process.GetCurrentProcess().Kill();
}
关于测试下载环境的搭建
新建 asp.net core webapi 项目
如同取消勾选
program.cs添加静态文件支持
app.UseStaticFiles();
重新生成代码
到debug目录下新建wwwroot文件夹
将用来测试的压缩包放到wwwroot文件夹下,注意以.zip的格式结尾
回到程序目录双击启动
在浏览器输入http://localhost:5000/v3.23.12_202312051713.zip,回车测试下载服务是否正常
可以看到成功下载了压缩包,至此下载环境搭建完成
代码地址