前言
我能抽象出整个世界,但是我不能抽象你。 想让你成为私有常量,这样外部函数就无法访问你。 又想让你成为全局常量,这样在我的整个生命周期都可以调用你。 可惜世上没有这样的常量,我也无法定义你,因为你在我心中是那么的具体。
哈喽大家好,本专栏为【项目实战】专栏,有别于【底层库】专栏,本专栏介绍项目开发过程中,遇到问题的解决方案,是我实际项目开发过程,相对成熟、可靠方法的提炼,我将这些问题的处理思路梳理,撰写本文分享给大家,大家遇到类似问题,可按本文方案处理。
本专栏会持续更新,不断完善,大家有任何问题,可以私信我。本专栏之间关联性较弱(文章之间依赖性较弱,没有阅读顺序区分)。如果您对本专栏感兴趣,欢迎关注吧,我将带你用最简洁的代码,实现最复杂的功能。
一、面临问题
顺接上期需求,客户要求【管理工具】能够自动更新,并且强调了一点:一定要悄悄的运行,不能影响用户操作,当发现新的版本时,才提醒“是否进行更新?”。
因此,我们做一个软件版本列表,记录当前使用的软件文件版本。和服务器的版本进行比对,不一致的情况下,自动下载最新版本至“临时文件夹”,当用户点击更新,我们才进行组件替换操作。本文主要是其中一个环节:记录软件版本列表。
二、解决方案
实现功能
① 获取组件(*.dll)的版本号、文件的MD5,用于和服务器文件校验。
② XML操作方法,读取、写入属性值。
③ 在一个XML文件中,分别记录组件(*.dll)版本号;文件(*.exe/*.config/*.xml等)的MD5值。
三、软件开发(源码展示)
创建类 VersionHelper.cs文件,复制以下代码:
/// <summary>
/// 获取源文件版本号
/// </summary>
/// <param name="a_strSourceFile"></param>
/// <returns></returns>
private static string GetFileVer(string a_strSourceFile)
{
string l_strRet = "";
try
{
FileVersionInfo ff = FileVersionInfo.GetVersionInfo(a_strSourceFile);
l_strRet = ff.FileVersion;
}
finally
{
GC.Collect();
}
return l_strRet;
}
/// <summary>
/// 获取源文件MD5值
/// </summary>
/// <param name="a_strSourceFile"></param>
/// <returns></returns>
private static string GetFileMD5(string a_strSourceFile)
{
System.Text.StringBuilder l_bfRet = new System.Text.StringBuilder();
System.IO.FileStream fs = new System.IO.FileStream(a_strSourceFile, System.IO.FileMode.Open,
FileAccess.Read, FileShare.ReadWrite);
try
{
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
md5.ComputeHash(fs);
foreach (byte b in md5.Hash)
{
l_bfRet.Append(string.Format("{0:X1}", b));
}
}
finally
{
fs.Close();
}
return l_bfRet.ToString();
}
#region 获取属性
/// <summary>
/// 取文件值(非*.dll文件)
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public string GetValueForFile(string key)
{
if (!File.Exists(this.FilePath))
{
File.WriteAllText(this.FilePath,UpdateXmlExtension.InitContent);
}
string result = "";
try
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(this.FilePath);
string xpath = "//file [@file_name=\"" + key + "\"]/@file_md5";
XmlNode xmlNode = xmlDocument.SelectSingleNode(xpath);
result = xmlNode.Value;
}
finally
{
}
return result;
}
/// <summary>
/// 取组件值(*.dll)
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public string GetValueForFun(string key)
{
if (!File.Exists(this.FilePath))
{
File.WriteAllText(this.FilePath,UpdateXmlExtension.InitContent);
}
string result = "";
try
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(this.FilePath);
string xpath = "//fun [@fun_no=\"" + key + "\"]/@assembly_ver";
XmlNode xmlNode = xmlDocument.SelectSingleNode(xpath);
result = xmlNode.Value;
}
finally
{
}
return result;
}
#endregion
#region 设置属性
/// <summary>
/// 设置值(非*.dll文件)
/// </summary>
/// <param name="a_strFunNo"></param>
/// <param name="a_strFileMD5"></param>
public void SetValueForFile(string a_strFunNo, string a_strFileMD5)
{
XmlDocument xmlDocument = new XmlDocument();
XmlElement xmlElement;
if (File.Exists(this.FilePath))//xml文件不存在
{
xmlDocument.Load(this.FilePath);//加载xml
XmlElement documentElement = xmlDocument.DocumentElement;
xmlElement = (documentElement.FirstChild as XmlElement);//定位第一个子节点
if(xmlElement == null)//没有该子节点,返回null
{
xmlElement = xmlDocument.CreateElement("FileList");//则创建FileList子节点
documentElement.AppendChild(xmlElement);
}
}
else
{
xmlDocument.AppendChild(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", ""));
xmlDocument.AppendChild(xmlDocument.CreateElement("configuration"));
XmlElement documentElement = xmlDocument.DocumentElement;
xmlElement = xmlDocument.CreateElement("FileList");
documentElement.AppendChild(xmlElement);
}
try
{
string l_strQuery = string.Format("//file [@file_name=\"{0}\"]", a_strFunNo);//例如://file [@file_name="K1"]"
XmlNode xmlNode = xmlDocument.SelectSingleNode(l_strQuery);//定位到该叶节点
if (xmlNode == null) {
XmlElement xmlElement2 = xmlDocument.CreateElement("file");//元素名
xmlElement2.SetAttribute("file_name", a_strFunNo);//设置属性
xmlElement2.SetAttribute("file_md5", a_strFileMD5);
xmlElement.AppendChild(xmlElement2);
} else {
XmlElement xmlElement2 = xmlNode as XmlElement;
xmlElement2.SetAttribute("file_name", a_strFunNo);
xmlElement2.SetAttribute("file_md5", a_strFileMD5);
}
}catch{
File.Delete(this.FilePath);
}
finally {
xmlDocument.Save(this.FilePath);
}
}
/// <summary>
/// 设置值(*.dll文件)
/// </summary>
/// <param name="a_strFunNo"></param>
/// <param name="a_strAssemblyVer"></param>
public void SetValueForFun(string a_strFunNo, string a_strAssemblyVer)
{
XmlDocument xmlDocument = new XmlDocument();
XmlElement xmlElement;
if (File.Exists(this.FilePath))
{
xmlDocument.Load(this.FilePath);
XmlElement documentElement = xmlDocument.DocumentElement;
xmlElement = (documentElement.SelectSingleNode("Presentation") as XmlElement);//定位名为"Presentation"子节点
if(xmlElement == null)
{
xmlElement = xmlDocument.CreateElement("Presentation");
documentElement.AppendChild(xmlElement);
}
}
else
{
xmlDocument.AppendChild(xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", ""));
xmlDocument.AppendChild(xmlDocument.CreateElement("configuration"));
XmlElement documentElement = xmlDocument.DocumentElement;
xmlElement = xmlDocument.CreateElement("Presentation");
documentElement.AppendChild(xmlElement);
}
try
{
string l_strQuery = string.Format("//fun [@fun_no=\"{0}\"]", a_strFunNo);
XmlNode xmlNode = xmlDocument.SelectSingleNode(l_strQuery);
if (xmlNode == null) {
XmlElement xmlElement2 = xmlDocument.CreateElement("fun");
xmlElement2.SetAttribute("fun_no", a_strFunNo);
xmlElement2.SetAttribute("assembly_ver", a_strAssemblyVer);
xmlElement.AppendChild(xmlElement2);
} else {
XmlElement xmlElement2 = xmlNode as XmlElement;
xmlElement2.SetAttribute("fun_no", a_strFunNo);
xmlElement2.SetAttribute("assembly_ver", a_strAssemblyVer);
}
}catch{
File.Delete(this.FilePath);
}
finally {
xmlDocument.Save(this.FilePath);
}
}
#endregion
四、运行效果
程序运行结果:
五、系列文章
C#项目--业务单据号生成器(定义规则、自动编号、流水号)
本文链接:C#项目--业务单据号生成器(定义规则、自动编号、流水号)_花北城的博客-CSDN博客
C#项目--开始日期结束日期范围计算(上周、本周、明年、前年等)
本文链接:C#项目--开始日期结束日期范围计算(上周、本周、明年、前年等)_c# 上周_花北城的博客-CSDN博客
C#项目--数据实体类使用
本文链接:C#底层库--数据实体类_c#实体类_花北城的博客-CSDN博客
C#项目--单据审批流方案
本文链接:C# 单据审批流方案_c# 审批流_花北城的博客-CSDN博客
C#项目--二维码标签制作及打印(完整版)
本文链接:C# 二维码标签制作及打印(完整版)_c# 打印标签_花北城的博客-CSDN博客
C#项目--条码管理操作手册
本文链接:条码管理操作手册_花北城的博客-CSDN博客
C#项目--WebAPI发布和IIS部署,及异常处理
本文链接:C# WebAPI项目发布和IIS部署_webapi发布到iis_花北城的博客-CSDN博客
C#项目--提高编程效率,代码自动生成
本文链接:C#提高编程效率--自动代码生成器_c# 代码生成器_花北城的博客-CSDN博客
C#项目--提高编程效率,Excel数据导入工具
本文链接:C#提高编程效率专辑—数据导入工具_c# 导表工具_花北城的博客-CSDN博客
C#项目--Windows服务(Service)安装及启停方案
本文链接:Windows服务(Service)安装及启动停止方案_windows服务安装_花北城的博客-CSDN博客
C#项目--穿透Session隔离,服务调用外部程序(无窗体界面解决)
本文链接:C#项目--穿透Session隔离,服务调用窗体程序(详细)_c# 服务打开程序没有界面_花北城的博客-CSDN博客
C#项目--任务计划实现,使用Quartz类
本文链接:Quartz封装任务计划管理类_花北城的博客-CSDN博客
C#项目--《周计划管理关于产前准备模块》解决方案20200203
本文链接:《周计划管理关于产前准备模块》解决方案20200203_花北城的博客-CSDN博客
C#项目--项目中,源码解析的正则表达式
本文链接:代码解析正则表达式_代码转换正则表达式_花北城的博客-CSDN博客
C#项目--如何获取文件版本和MD5值
本文链接:https://blog.csdn.net/youcheng_ge/article/details/112513871
C#项目--如何测试网络是否连通
本文链接:C#测试网络是否能够访问_花北城的博客-CSDN博客