博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.Net 配置的简陋解决方案
阅读量:5064 次
发布时间:2019-06-12

本文共 13532 字,大约阅读时间需要 45 分钟。

    公司是做CS产品的, 最近分配给我一个活, 要求:

    1. 公司程序启动时, 检测是否有配置文件, 没有的话则按默认值创建一个
    2. 配置文件要加密, 不能让客户随便看到里面的参数
    3. 配置文件要有配套的GUI配置工具, 因为现场实施人员嫌XML配置麻烦
    如果只有一个产品需要这个功能, 把每个配置项的读写功能硬编码写到工具里就完事了, 但公司有好几个产品都需要这个, 不得不写一个通用的工具类
    这个工作还解决了两个问题:
    a. 以前设置项都配置在 app.config 里, 每次升级都会覆盖原来的设置, 所以现场人员都必须先将 app.config复制出来.
    b. app.config 里新增了配置项, 现场实施人员必须仔细对比, 将新增项人工放入原来的app.config
    现在的做法是, 配置文件ConfigSetting.xml并不在安装包中, 所以卸载升级都不会影响它; 程序第一次启动时, 会按默认值生成一个ConfigSetting.xml; 以后程序启动的时候, 假如有新增的配置项, 则将其加入ConfigSetting.xml
    我把涉及的两个类都放在了一个文件, 这样引入一个文件即可

using System;    using System.Collections.Generic;    using System.Xml.Linq;    using System.Security.Cryptography;    using System.IO;    ///     /// 设置项的帮助类    ///     public class ConfigSettingTool    {        ///         /// 保存读取时, 是否加密解密; 设为false, 可以方便调试        /// 其实也只能防小白, 随便反编译一下就啥都漏出来了        ///         private static bool isEncrypt = false;        ///         /// 默认的配置文件名        ///         public static readonly string DefaultXmlFileName = "ConfigSetting.xml";        ///         /// 获取XDocument, 解密失败、XML结构不合理, 都会根据模板重新生成一个        ///         ///         ///         /// 
确保返回如下格式 ///
///
///
///
///
public static XDocument GetXDocument(string xmlFileName, out string msg) { msg = null; if (!System.IO.File.Exists(xmlFileName)) { msg = "配置文件不存在, 创建默认配置文件"; return new XDocument(new XDeclaration("1.0", "utf-8", "yes"), new XElement("Setting", new XElement("SingleSetting"))); } try { var textContent = System.IO.File.ReadAllText(xmlFileName); textContent = isEncrypt ? Decrypt(textContent) : textContent; var xdoc = XDocument.Parse(textContent); if (xdoc.Root.Name != "Setting") { throw new Exception("根节点不是 Setting"); } if (xdoc.Root.Element("SingleSetting") == null) { throw new Exception("没有 SingleSetting 节点"); } return xdoc; } catch { msg = "配置文件不是标准格式, 删除后, 创建默认配置文件"; return new XDocument(new XDeclaration("1.0", "utf-8", "yes"), new XElement("Setting", new XElement("SingleSetting"))); } } /// /// 将xml信息读出到settingArray, 如果缺少某项设定则增加到xdoc /// /// /// 通常就是GlobalSetting.DefaultGlobalSettingArray public static void ReadValueToSettingArray(XDocument xdoc, List
settingArray) { var singleSettingElement = xdoc.Root.Element("SingleSetting"); foreach (var configureItem in settingArray) { configureItem.ErrorMsg = null; var element = singleSettingElement.Element(configureItem.Name); if (element == null) { element = new XElement(configureItem.Name, configureItem.DefaultValue, new XAttribute("Caption", configureItem.Caption), new XAttribute("Description", configureItem.Description), new XAttribute("DefaultValue", configureItem.DefaultValue), new XAttribute("CanBeEmpty", configureItem.CanBeEmpty)); singleSettingElement.Add(element); } configureItem.Value = string.IsNullOrWhiteSpace(element.Value) ? "" : element.Value.Trim(); } } ///
/// 将xml信息读出到settingArray /// ///
///
通常就是GlobalSetting.DefaultGlobalSettingArray public static void ReadConfig(XDocument xdoc, out List
settingList) { settingList = new List
(); var singleSettingElement = xdoc.Root.Element("SingleSetting"); foreach (var element in singleSettingElement.Elements()) { var captionAttribute = element.Attribute("Caption"); var caption = captionAttribute != null ? captionAttribute.Value : ""; var name = element.Name.ToString(); var value = element.Value.ToString(); var descriptionAttribute = element.Attribute("Description"); var description = descriptionAttribute != null ? descriptionAttribute.Value : ""; var defaultValueAttribute = element.Attribute("DefaultValue"); var defaultValue = defaultValueAttribute != null ? defaultValueAttribute.Value : ""; var canBeEmpty = false; try { canBeEmpty = bool.Parse(element.Attribute("CanBeEmpty").Value); } catch { } var errorMsgAttribute = element.Attribute("ErrorMsg"); var errorMsg = errorMsgAttribute != null ? errorMsgAttribute.Value : ""; var configureItem = new ConfigureItemModel(caption, name, defaultValue, description, canBeEmpty) { Value = value, ErrorMsg = errorMsg }; settingList.Add(configureItem); } } ///
/// 尝试解析设置内容 到 目标class /// ///
通常就是GlobalSetting.DefaultGlobalSettingArray, 配置项设置不合理时, 会将错误信息保存到ErrorMsg ///
通常就是GlobalSetting ///
成功, true; 失败: false
public static bool TryParseConfig(List
settingArray, Type targetSettingClass) { bool isAllSuccess = true; foreach (var configureItem in settingArray) { configureItem.ErrorMsg = null; configureItem.Value = string.IsNullOrWhiteSpace(configureItem.Value) ? "" : configureItem.Value.Trim(); if (configureItem.Value == "" && configureItem.CanBeEmpty == false) { configureItem.ErrorMsg += "该项值不能为空, 请手动填写该值;"; isAllSuccess = false; continue; } var property = targetSettingClass.GetProperty(configureItem.Name); //如果 targetSettingClass 没有对应的静态属性, 则跳过 if (property == null) { continue; } object value = null; try { value = Convert.ChangeType(configureItem.Value, property.PropertyType); property.SetValue(null, value, null); } catch { configureItem.ErrorMsg += configureItem.Value + "不能转换为" + property.PropertyType.Name + ", 请重新填写该值;"; isAllSuccess = false; continue; } } return isAllSuccess; } ///
/// 写入 /// ///
///
通常就是GlobalSetting.DefaultGlobalSettingArray ///
成功, null
public static bool TrySaveToXML(string xmlFileName, List
settingArray, out string msg) { msg = null; var xdoc = GetXDocument(xmlFileName, out msg);//原文件读出错误, 忽略即可, 因为settingArray会自动填充 var singleSettingElement = xdoc.Root.Element("SingleSetting"); foreach (var configureItem in settingArray) { var element = singleSettingElement.Element(configureItem.Name); if (element == null) { element = new XElement(configureItem.Name, configureItem.Value); singleSettingElement.Add(element); } else { element.Value = configureItem.Value ?? ""; } element.RemoveAttributes(); element.Add(new XAttribute("Caption", configureItem.Caption)); element.Add(new XAttribute("Description", configureItem.Description)); element.Add(new XAttribute("DefaultValue", configureItem.DefaultValue)); element.Add(new XAttribute("CanBeEmpty", configureItem.CanBeEmpty)); if (!string.IsNullOrWhiteSpace(configureItem.ErrorMsg)) { element.Add(new XAttribute("ErrorMsg", configureItem.ErrorMsg)); } } var textContent = xdoc.ToString(); textContent = isEncrypt ? Encrypt(textContent) : textContent; try { System.IO.File.WriteAllText(xmlFileName, textContent); return true; } catch (Exception ex) { msg= "保存失败:" + ex.Message; return false; } } #region 加密解密部分 private static byte[] DESKey = new byte[] { 11, 69, 93, 102, 172, 41, 18, 12 }; private static byte[] DESIV = new byte[] { 75, 77, 46, 197, 78, 157, 23, 36 }; ///
/// 加密 /// private static string Encrypt(string source) { string reValue = ""; DESCryptoServiceProvider objDes = new DESCryptoServiceProvider(); MemoryStream objMemoryStream = new MemoryStream(); CryptoStream objCrytoStream = new CryptoStream(objMemoryStream, objDes.CreateEncryptor(DESKey, DESIV), CryptoStreamMode.Write); StreamWriter objStreamWriter = new StreamWriter(objCrytoStream); objStreamWriter.Write(source); objStreamWriter.Flush(); objCrytoStream.FlushFinalBlock(); objMemoryStream.Flush(); reValue = Convert.ToBase64String(objMemoryStream.GetBuffer(), 0, (int)objMemoryStream.Length); return reValue; } ///
/// 解密 /// private static string Decrypt(string source) { string reValue = ""; DESCryptoServiceProvider objDES = new DESCryptoServiceProvider(); byte[] Input = Convert.FromBase64String(source); MemoryStream objMemoryStream = new MemoryStream(Input); CryptoStream objCryptoStream = new CryptoStream(objMemoryStream, objDES.CreateDecryptor(DESKey, DESIV), CryptoStreamMode.Read); StreamReader objStreamReader = new StreamReader(objCryptoStream); reValue = objStreamReader.ReadToEnd(); return reValue; } #endregion } ///
/// 单个设置项 /// ///
由于XML中不能保存null, 所以所有属性都不会被设置为null
public class ConfigureItemModel { ///
/// 单个设置项 /// ///
显示名称 ///
参数名称 ///
默认值 ///
描述, 该项不设定时候, 显示默认值 ///
能否为空字符串 public ConfigureItemModel(string captionParam, string nameParam, string defaultValueParam, string descriptionParam = "", bool canBeEmptyParam = false) { Caption = captionParam; Name = nameParam; Description = descriptionParam; DefaultValue = defaultValueParam; CanBeEmpty = canBeEmptyParam; } private string caption = ""; ///
/// 显示名称 /// public string Caption { get { return caption; } set { caption = string.IsNullOrWhiteSpace(value) ? "" : value; } } private string name = ""; ///
/// 参数名称 /// public string Name { get { return name; } set { name = string.IsNullOrWhiteSpace(value) ? "" : value; ; } } private string description = ""; ///
/// 说明, 如果该值没有赋值, 则显示DefaultValue /// public string Description { get { return string.IsNullOrWhiteSpace(description) ? defaultValue : description; } set { description = string.IsNullOrWhiteSpace(value) ? "" : value; } } private string defaultValue = ""; ///
/// 默认值 /// public string DefaultValue { get { return defaultValue; } set { defaultValue = string.IsNullOrWhiteSpace(value) ? "" : value; } } ///
/// 能否为空字符串 /// public bool CanBeEmpty { get; set; } ///
/// 能否为空字符串 的字符串形式 /// public string CanBeEmptyString { get { return CanBeEmpty ? "是" : "否"; } } private string innerValue = ""; ///
/// 值 /// public string Value { get { return innerValue; } set { innerValue = string.IsNullOrWhiteSpace(value) ? "" : value; ; } } private string errorMsg = ""; ///
/// 错误信息 /// public string ErrorMsg { get { return errorMsg; } set { errorMsg = string.IsNullOrWhiteSpace(value) ? "" : value; ; } } }
View Code

 

   产品里建一个 GlobalSetting 类, 里面的配置项都必须是  static 属性, 然后加入 public static List<ConfigureItemModel> DefaultGlobalSettingArray 保存默认设置

///     /// 全局设定    ///     /// 
所有属性都必须是 static , 即 类属性
public class GlobalSetting { public static List
DefaultGlobalSettingArray = new List
() { new ConfigureItemModel("数据库的主机地址","ConnectionStringHost", "127.0.0.1"), }; ///
/// 数据库的主机地址 /// public static string ConnectionStringHost { get; set; } }
View Code

 

  具体的示例请参考 ConfigSettingToolTest, 第一次运行时会报错: 升级地址 不能为空, 使用  配置文件编辑工具2.exe 为其赋值后, 就可以正常启动了

 

             

 

转载于:https://www.cnblogs.com/zhouandke/p/8676278.html

你可能感兴趣的文章
IOS-图片操作集合
查看>>
Android bitmap图片处理
查看>>
Android应用程序进程启动过程的源代码分析
查看>>
adb logcat 命令行用法
查看>>
Redis学习手册(Key操作命令)
查看>>
模板统计LA 4670 Dominating Patterns
查看>>
泛型第23条:请不要在新代码中使用原生态类型
查看>>
非对称加密
查看>>
bzoj 3413: 匹配
查看>>
从下周开始就要采用网上记录值班日志了
查看>>
在qq中可以使用添加标签功能
查看>>
eclipse 自定义布局
查看>>
团队项目开发客户端——登录子系统的设计
查看>>
【AppScan心得】IBM Rational AppScan 无法记录登录序列
查看>>
[翻译] USING GIT IN XCODE [4] 在XCODE中使用GIT[4]
查看>>
简化通知中心的使用
查看>>
SpringMVC的@Validated校验注解使用方法
查看>>
Python之os模块
查看>>
IO—》Properties类&序列化流与反序列化流
查看>>
【蓝桥杯】PREV-21 回文数字
查看>>