C/S架构系统的自动更新功能设计与实现(二)

核心代码类设计

文件单元

我们将版本的每一个文件视为一个文件单元,需要获取其相对路径、大小、版本、写操作时间、MD5码等信息。结构定义(含方法):

/// <summary>
/// 文件信息
/// </summary>
public class FileUnit : IComparable<FileUnit>
{
	/// <summary>
	/// 
	/// </summary>
	public FileUnit() { }

	/// <summary>
	/// 
	/// </summary>
	/// <param name="sDirectory">此版本的根目录,如"D:\\MyApp\\MyApp_Build_201906117"</param>
	/// <param name="sFullPath">此文件的全路径如"D:\\MyApp\\MyApp_Build_201906117\\Main.exe"</param>
	public FileUnit(string sDirectory, string sFullPath)
	{
		RelativePath = sFullPath.Substring(sDirectory.Length).TrimStart('\\');
		Version = GetFileVersion(sFullPath);
		var fileInfo = new FileInfo(sFullPath);
		FileSize = (int)(fileInfo.Length / 1024);
		LastUpgradeTime = fileInfo.LastWriteTime;
		Md5Code = GlobalHelper.GetMD5FromFile(sFullPath);
	}
	/// <summary>
	/// 
	/// </summary>
	/// <param name="sRelativePath">文件的相对路径,如"Main.exe"</param>
	/// <param name="sVersion">版本号</param>
	/// <param name="lSize">文件大小(单位:KB)</param>
	/// <param name="dtUpdateTime">更新时间(文件的最后写入时间)</param>
	public FileUnit(string sRelativePath, string sVersion, long lSize, DateTime dtUpdateTime)
	{
		RelativePath = sRelativePath;
		Version = sVersion;
		FileSize = lSize;
		LastUpgradeTime = dtUpdateTime;
	}
	/// <summary>
	/// 文件的相对路径
	/// </summary>
	[JsonProperty("path")]
	public string RelativePath { get; set; }
	/// <summary>
	/// 文件大小(单位:KB)
	/// </summary>
	[JsonProperty("size")]
	public long FileSize { get; set; } = 0;
	/// <summary>
	/// 更新时间
	/// </summary>
	[JsonConverter(typeof(CustomizedDateTimeConverter))]
	[JsonProperty("time")]
	public DateTime LastUpgradeTime { get; set; } = DateTime.Now;
	/// <summary>
	/// 文件版本
	/// </summary>
	[JsonProperty("version")]
	public string Version { get; set; }

	/// <summary>
	/// 文件MD5码
	/// </summary>
	[JsonProperty("md5")]
	public string Md5Code { get; set; }

	/// <summary>
	/// 获取文件的版本信息
	/// </summary>
	/// <param name="sFileName">文件的完整路径</param>
	/// <returns></returns>
	public static FileVersionInfo GetFileVersionInfo(string sFileName) => FileVersionInfo.GetVersionInfo(sFileName);

	/// <summary>
	/// 获取文件的版本号
	/// </summary>
	/// <param name="sFileName">文件的完整路径</param>
	/// <returns></returns>
	public static string GetFileVersion(string sFileName) => GetFileVersionInfo(sFileName)?.FileVersion ?? "0.0.0.0";

	/// <summary>
	/// 获取最近更新时间
	/// </summary>
	/// <param name="sFileName">文件的完整路径</param>
	/// <returns></returns>
	public static DateTime GetLatestTime(string sFileName)
	{
		var fileInfo = new FileInfo(sFileName);
		return fileInfo.LastWriteTime;
	}

	/// <summary>
	/// 版本B是否比版本A新
	/// </summary>
	/// <param name="VersionA"></param>
	/// <param name="VersionB"></param>
	/// <returns></returns>
	public static bool NewerThanVersionA(FileVersionInfo VersionA, FileVersionInfo VersionB)
	{
		var bNew = false;
		try
		{
			bNew = NewerThanVersionA(VersionA.ToString(), VersionB.ToString());
		}
		catch { }
		return bNew;
	}
	/// <summary>
	/// 版本B是否比版本A新
	/// </summary>
	/// <param name="sVersionA"></param>
	/// <param name="sVersionB"></param>
	/// <returns></returns>
	public static bool NewerThanVersionA(string sVersionA, string sVersionB)
	{
		var bNew = false;
		try
		{
			var lstCurrentVersion = sVersionA.Split('.');
			var lstOtherVersion = sVersionB.Split('.');
			var nLen = lstCurrentVersion.Length > lstOtherVersion.Length ? lstOtherVersion.Length : lstCurrentVersion.Length;
			for (int i = 0; i < nLen; i++)
			{
				if (!int.TryParse(lstOtherVersion[i], out int nOtherVersion) ||
					!int.TryParse(lstCurrentVersion[i], out int nCurrentVersion) ||
					nOtherVersion <= nCurrentVersion)
				{
					continue;
				}
				bNew = true;
				break;
			}
			if (!bNew && lstOtherVersion.Length - lstCurrentVersion.Length > 0)
			{
				for (int i = lstCurrentVersion.Length - 1; i < lstOtherVersion.Length; i++)
				{
					if (!int.TryParse(lstOtherVersion[i], out int nOtherVersion) || nOtherVersion <= 0)
						continue;
					bNew = true;
					break;
				}
			}
		}
		catch { }
		return bNew;
	}
	/// <summary>
	/// 是否相等(比较文件MD5码)
	/// </summary>
	/// <param name="obj"></param>
	/// <returns></returns>
	public override bool Equals(object obj)
	{
		if (!(obj is FileUnit fileUnit) || string.IsNullOrEmpty(fileUnit.Md5Code) || string.IsNullOrEmpty(Md5Code))
		{
			return false;
		}
		return fileUnit.Md5Code.Equals(Md5Code);
	}
	/// <summary>
	/// 
	/// </summary>
	/// <param name="other"></param>
	/// <returns></returns>
	public int CompareTo(FileUnit other)
	{
		return RelativePath.CompareTo(other.RelativePath);
	}
	/// <summary>
	/// 获取文件HashCode
	/// </summary>
	/// <returns></returns>
	public override int GetHashCode()
	{
		return RelativePath.GetHashCode();
	}
}

升级信息

完整版

/// <summary>
/// 升级信息(完整版)
/// </summary>
public class UpgradeInfo
{
	public UpgradeInfo() { }
	/// <summary>
	/// 配置文件路径
	/// </summary>
	[JsonIgnore]
	public static string ConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "upgrade.json");

	private readonly object lockObject = new object();

	private string _mainVersion = "";
	/// <summary>
	/// 此版本的主版本号
	/// </summary>
	[JsonProperty("version")]
	public string MainVersion
	{
		get
		{
			if (null != MainVersionInfo)
				_mainVersion = MainVersionInfo.FileVersion;
			return _mainVersion;
		}
		set { _mainVersion = value; }
	}
	/// <summary>
	/// 此版本的主版本信息
	/// </summary>
	[JsonIgnore]
	public FileVersionInfo MainVersionInfo { get; set; }

	private int totalCount = 0;
	/// <summary>
	/// 此版本文件总数
	/// </summary>
	[JsonProperty("count")]
	public int TotalCount
	{
		get
		{
			if (FileUnits.Count > 0)
				totalCount = FileUnits.Count;
			return totalCount;
		}
		set { totalCount = value; }
	}

	private long totalSize = 0;
	/// <summary>
	/// 此版本文件总大小(单位:KB)
	/// </summary>
	[JsonProperty("size")]
	public long TotalSize
	{
		get
		{
			if (FileUnits.Count > 0)
			{
				totalSize = 0;
				foreach (var item in FileUnits)
				{
					totalSize += item.FileSize;
				}
			}
			return totalSize;
		}
		set { totalSize = value; }
	}

	private DateTime lastUpgradeTime = DateTime.MinValue;
	/// <summary>
	/// 最后更新时间
	/// </summary>
	[JsonProperty("time")]
	[JsonConverter(typeof(CustomizedDateTimeConverter))]
	public DateTime LastUpgradeTime
	{
		get
		{
			if (0 < FileUnits.Count)
			{
				var dateTime = DateTime.MinValue;
				foreach (var item in FileUnits)
				{
					if (item.LastUpgradeTime > dateTime)
						dateTime = item.LastUpgradeTime;
				}
				lastUpgradeTime = dateTime;
			}
			return lastUpgradeTime;
		}
		set { lastUpgradeTime = value; }
	}
	/// <summary>
	/// 此版本的文件列表
	/// </summary>
	[JsonProperty("files")]
	public IList<FileUnit> FileUnits { get; set; } = new List<FileUnit>();

	/// <summary>
	/// 保存配置信息
	/// </summary>
	/// <param name="sConfigurationPath">配置文件路径(为空时取默认路径)</param>
	public void Save(string sConfigurationPath = null)
	{
		try
		{
			lock (lockObject)
			{
				if (!string.IsNullOrEmpty(sConfigurationPath) && File.Exists(sConfigurationPath))
					ConfigurationPath = sConfigurationPath;
				var fileStream = File.Open(ConfigurationPath, FileMode.Create, FileAccess.ReadWrite);
				var sValue = JsonConvert.SerializeObject(this);
				var byteContent = System.Text.Encoding.Default.GetBytes(sValue);
				fileStream.Write(byteContent, 0, byteContent.Length);
				fileStream.Flush();
				fileStream.Close();
			}
		}
		catch { }
	}

	/// <summary>
	/// 加载配置信息
	/// </summary>
	/// <param name="sConfigurationPath">配置文件路径(为空时取默认路径)</param>
	public void Load(string sConfigurationPath = null)
	{
		try
		{
			lock (lockObject)
			{
				if (!string.IsNullOrEmpty(sConfigurationPath) && File.Exists(sConfigurationPath))
					ConfigurationPath = sConfigurationPath;
				var upgradeInfo = JsonConvert.DeserializeObject<UpgradeInfo>(File.ReadAllText(ConfigurationPath, System.Text.Encoding.Default));
				MainVersionInfo = upgradeInfo.MainVersionInfo;
				MainVersion = upgradeInfo.MainVersion;
				TotalCount = upgradeInfo.TotalCount;
				TotalSize = upgradeInfo.TotalSize;
				FileUnits = upgradeInfo.FileUnits;
			}
		}
		catch(Exception ex)
		{
			Log.Loging.Error(ex.Message);
		}
	}
}

其中,时间格式转换类为:

/// <summary>
/// 时间格式转换
/// </summary>
public class CustomizedDateTimeConverter : DateTimeConverterBase
{
	private static readonly IsoDateTimeConverter DtConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };

	public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
	{
		DtConverter.WriteJson(writer, value, serializer);
	}

	public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
	{
		return DtConverter.ReadJson(reader, objectType, existingValue, serializer);
	}
}

仅摘要

	/// <summary>
	/// 此版本的主版本信息
	/// </summary>
	[JsonIgnore]
	public FileVersionInfo MainVersionInfo { get; set; }
	/// <summary>
	/// 此版本的主版本号
	/// </summary>
	[JsonProperty("version")]
	public string MainVersion { get; set; }
	/// <summary>
	/// 此版本文件总数
	/// </summary>
	[JsonProperty("count")]
	public int TotalCount { get; set; }

	/// <summary>
	/// 此版本文件总大小(单位:字节)
	/// </summary>
	[JsonProperty("size")]
	public long TotalSize { get; set; }

	/// <summary>
	/// 最后更新时间
	/// </summary>
	[JsonProperty("time")]
	[JsonConverter(typeof(CustomizedDateTimeConverter))]
	public DateTime LastUpgradeTime { get; set; }
}

文件对象集合

/// <summary>
/// 升级信息(仅新版本所有文件信息)
/// </summary>
public class UpgradeFilesInfo
{
	public UpgradeFilesInfo() { }

	public UpgradeFilesInfo(UpgradeInfo upgradeInfo)
	{
		FileUnits = upgradeInfo.FileUnits;
	}

	/// <summary>
	/// 此版本的文件列表
	/// </summary>
	[JsonProperty("files")]
	public IList<FileUnit> FileUnits { get; set; } = new List<FileUnit>();
}

响应消息

/// <summary>
/// 返回结果中的错误代码。
/// 0表示OK,其他均表示错误。
/// 错误码区码代码段,如:
/// 1-9表示一大类不同小类的错误,
/// 11-19表示一大类不同小类的错误,
/// 21-29表示一大类不同小类的错误……
/// 依此类推。
/// 通用错误(不细分类型)码为较大的数,如999
/// </summary>
public enum ErrorCode
{
	/// <summary>
	/// 未知错误
	/// </summary>
	[Description("未知错误")]
	Unknown = -1,
	/// <summary>
	/// 成功
	/// </summary>
	[Description("成功")]
	Ok = 0,
	/// <summary>
	/// 非法参数
	/// </summary>
	[Description("非法参数")]
	InvalidParam = 1,
	/// <summary>
	/// 常见错误
	/// </summary>
	[Description("常见错误")]
	CommonError = 999
}

public interface IResponseBody
{
	ErrorCode Code { get; set; }
	string Description { get; set; }

	object Data { get; set; }
}

/// <summary>
/// 返回结果
/// </summary>
public class ResponseInfo : IResponseBody
{
	/// <summary>
	/// 状态码
	/// </summary>
	[JsonProperty("code")]
	[JsonRequired]
	[DefaultValue(ErrorCode.Unknown)]
	public ErrorCode Code { get; set; }

	private string _description;
	/// <summary>
	/// 描述信息
	/// </summary>
	[JsonProperty("desc")]
	public string Description
	{
		get
		{
			if (string.IsNullOrEmpty(_description))
				_description = EnumTypeHelper.GetEnumDescription(Code);
			return _description;
		}
		set
		{
			_description = value;
		}
	}
	/// <summary>
	/// 数据
	/// </summary>
	[JsonProperty("data", NullValueHandling = NullValueHandling.Include)]
	public object Data { get; set; }
}

/// <inheritdoc />
/// <summary>
/// 成功
/// </summary>
public sealed class ResponseOk : ResponseInfo
{
	public ResponseOk() { Code = ErrorCode.Ok; }
}


public class ResponseCommonError : ResponseInfo
{
	public ResponseCommonError() { Code = ErrorCode.CommonError; }
}
/// <inheritdoc />
/// <summary>
/// 出错
/// </summary>
public sealed class ResponseError : ResponseCommonError
{
	public ResponseError(Exception e) { Description = e.Message; }
	public ResponseError(string desc) { Description = desc; }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值