《企业考试系统》项目实践(04):通用工具类库之配置文件操作工具
摘要:对于应用程序的配置方法进行说明,并使用自定义的XML格式的文件做为《考试系统》的配置文件。
应用程序配置的方法
对于应用程序(无论是Windows应用程序还是Web应用程序),其应用程序配置非常重要。现今在开发中有一种说法,叫“配置驱动”,其含义是使用配置来驱动整个应用程序的运行。通常将应用程序运行过程中可能会变化的(如对于数据库连接的连接字符串),需要保存的数据(如打开或保存文件的历史记录)均应做为配置保存。
对于应用程序的配置,其基本特点有:
- 可持久化,即当应用程序重新启动或计算机重新启动后,配置应仍然存在。
- 更改配置的内容,在应用程序不重新编译的前提下可以更改应用程序执行的内容(如多语言版本的应用程序,更改其显示的语言,即更改配置,应用程序不需要重新编译即可以更改其显示的语言)
常见的应用程序的配置有以下几种方法:
配置文件
即将配置以文件的形式保存。这是应用程序配置的最常见的做法。配置文件又根据其文件格式分为以下几种:
- 二进制文件
以二进制方式保存配置的数据,其优点在于读写的速度快,更灵活;其缺点是更改不方便(但需要对于配置进行保密时可以是优点),操作较为麻烦。例如一些游戏的存档文件是以二进制方式保存的,一些所有的存档修改器就是将其二进制位的数值进行更改,如某位置的两个字节表示的是生命值,将0001更改为00FF便将生命值是1提升到256。另外对于二进制的数据还可以方便的对于进行加密或压缩操作。 - 纯文本INI格式的文件
纯文本格式的配置文件的优点在于便于修改,且与操作系统、编程语言无关。早期的操作系统或应用程序的配置采用的是纯文本的INI格式,例如Windows XP、Windows Server 2003及以前的操作系统C盘根目录中有一个系统隐藏文件boot.ini,其内容如下:1: [boot loader]
2: timeout=30
3: default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
4: [operating systems]
5: multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows Server 2003, Standard" /noexecute=optout /fastdetect
在.Net Framework中没有对其进行读写操作的方法,可以将其按纯文本读取,按字符串进行拆分。
- 纯文本XML格式的文件
XML文件是现在应用程序中采用比较多的配置文件的保存格式,其优点在于格式清晰,可以对于内容进行相应的约束(Xml Schema或DTD)。对于XML格式的配置文件的操作大多采用XmlDocument对象进行操作。本系统便是采用这种方式操作配置文件。 - 序列化文件
序列化可以看作生成配置文件的一种方法,可以将需要保存的数据封装到一个或多个可序列化的类型中,将其实例序列化为二进制格式或SOAP格式的文件,将此文件做为配置文件,在读取配置时,直接反序列化这个文件,恢复实例即可。 - .Net应用程序配置文件
在.Net应用程序中的“应用程序配置文件”,即App.config或web.config文件,其对于用户的配置操作有两种,一种是AppSetting节,另一种是“设置”。两种方法各有优点,在Framework 2.0以后,大多数使用“设置”。
注册表
即将需要保存的数据使用RegistryKey对象,保存到系统注册表中。但不建议使用。(避免产生大量的注册表垃圾)
Web应用程序中的Cookie、Profile
将一些信息保存在Cookie或Profile中,这种在Web应用程序中常见,特别是Cookie。
数据库
将配置信息保存在数据库中。例如BBS系统中的用户的配置等。
《企业考试系统》配置文件工具类
《企业考试系统》的配置采用XML格式的配置文件,其配置文件的格式如下:
- 根节点为configurations
- 根节点的每一个config子节点表示一个配置项,其中包含三个属性:key表示配置项的名,value表示配置项的值,isCrypt表示配置项的值是否加密
定义一个通用的类型,用来操作此配置文件的读写:
1: using System;
2: using System.Xml;
3: using CommonUtilityLibrary.SymmetricCryptography;
4:
5: namespace CommonUtilityLibrary.Configuration
6: {
7: /// <summary>
8: /// 配置文件操作工具类
9: /// <![CDATA[
10: /// 配置文件的格式
11: /// <? xml version="1.0" ?>
12: /// <configurations>
13: /// <!--
14: /// 每个配置项对应一个config节点,每个节点中
15: /// key:对应配置项的名
16: /// value:对应配置项的值
17: /// isCrypt:对应配置项是否加密,值为True/False
18: /// -->
19: /// <config key="" value="" isCrypt="" />
20: /// </configurations>
21: /// ]]>
22: /// </summary>
23: public sealed class ConfigurationUtility
24: {
25: /// <summary>
26: /// 配置文件的文件名
27: /// </summary>
28: private readonly string configFileName;
29:
30: /// <summary>
31: /// XmlDocument对象
32: /// </summary>
33: private readonly XmlDocument document;
34:
35: /// <summary>
36: /// 加密工具类
37: /// </summary>
38: private readonly SymmetricCryptographyUtility cryptUtility;
39:
40: #region 配置文件中各配置项节点的名称
41: private const string ROOT_NODE_NAME = "configurations";
42: private const string CONFIG_NODE_NAME = "config";
43: private const string KEY_ATTRIBUTE_NAME = "key";
44: private const string VALUE_ATTRIBUTE_NAME = "value";
45: private const string ISCRYPT_ATTRIBUTE_NAME = "isCrypt";
46: #endregion
47:
48: /// <summary>
49: /// 构造方法,使用自定义的加密工具类实例
50: /// </summary>
51: /// <param name="configFileName">配置文件的文件名</param>
52: /// <param name="utility">加密工具类实例</param>
53: public ConfigurationUtility(
54: string configFileName, SymmetricCryptographyUtility utility)
55: {
56: this.configFileName = configFileName;
57:
58: cryptUtility = utility;
59:
60: document = new XmlDocument();
61:
62: document.Load(configFileName);
63: }
64:
65: /// <summary>
66: /// 查找配置文件中的配置项
67: /// </summary>
68: /// <param name="key">配置项的名</param>
69: /// <returns>返回相应配置项的XmlNode,如没有相应节点,则返回null</returns>
70: private XmlNode GetXmlNodeByKey(string key)
71: {
72: document.Load(configFileName);
73: XmlNode result = null;
74: if (document != null)
75: foreach (XmlNode node in document[ROOT_NODE_NAME])
76: {
77: if (node.NodeType != XmlNodeType.Element)
78: {
79: continue;
80: }
81:
82: if (node.Attributes[KEY_ATTRIBUTE_NAME].Value == key)
83: {
84: result = node;
85: break;
86: }
87: }
88: return result;
89: }
90:
91: /// <summary>
92: /// 设置配置项(如配置项不存在则添加;如存在则修改)
93: /// </summary>
94: /// <param name="key">配置项的名</param>
95: /// <param name="value">配置项的值</param>
96: /// <param name="isCrypt">配置项是否加密</param>
97: public void SetConfiguration(string key, string value, bool isCrypt)
98: {
99: if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value))
100: {
101: throw new ArgumentNullException();
102: }
103:
104: if (isCrypt)
105: {
106: value = cryptUtility.EncryptBase64String(value);
107: }
108:
109: XmlNode node = GetXmlNodeByKey(key);
110:
111: if (node != null)
112: {
113: // 修改配置项
114: node.Attributes[VALUE_ATTRIBUTE_NAME].Value = value;
115: node.Attributes[ISCRYPT_ATTRIBUTE_NAME].Value = isCrypt.ToString();
116: }
117: else
118: {
119: // 添加配置项
120: XmlElement element = document.CreateElement(CONFIG_NODE_NAME);
121: element.SetAttribute(KEY_ATTRIBUTE_NAME, key);
122: element.SetAttribute(VALUE_ATTRIBUTE_NAME, value);
123: element.SetAttribute(ISCRYPT_ATTRIBUTE_NAME, isCrypt.ToString());
124:
125: document[ROOT_NODE_NAME].AppendChild(element);
126: }
127:
128: document.Save(configFileName);
129: }
130:
131: /// <summary>
132: /// 获取配置项的值
133: /// </summary>
134: /// <param name="key">配置项的名</param>
135: /// <returns>返回配置项的值,如果配置项不存在,返回null</returns>
136: public string GetConfiguration(string key)
137: {
138: if (string.IsNullOrEmpty(key))
139: {
140: throw new ArgumentNullException();
141: }
142:
143: XmlNode node = GetXmlNodeByKey(key);
144:
145: string result = null;
146:
147: if (node != null)
148: {
149: string value = node.Attributes[VALUE_ATTRIBUTE_NAME].Value;
150:
151: if (bool.Parse(node.Attributes[ISCRYPT_ATTRIBUTE_NAME].Value))
152: {
153: value = cryptUtility.DecryptBase64String(value);
154: }
155:
156: result = value;
157: }
158:
159: return result;
160: }
161: }
162: }
其类型成员及说明如下:
- 构造方法:两个参数,一个表示配置文件的文件名,另一个为配置文件需要加密时使用的加密工具类
- SetConfiguration方法,添加或修改配置项的值
- GetConfiguration方法,获取某配置项的值,如配置项加密,则返回解密后的值
建立对配置文件操作的测试类,测试类代码如下:
1: using System;
2: using System.IO;
3: using CommonUtilityLibrary.Configuration;
4: using CommonUtilityLibrary.SymmetricCryptography;
5: using Microsoft.VisualStudio.TestTools.UnitTesting;
6:
7:
8: namespace ExamSolution.SolutionUnitTestProject.CommonUtilityLibrary.Configuration
9: {
10: /// <summary>
11: /// 配置文件操作工具类测试
12: /// </summary>
13: [TestClass]
14: public class ConfigurationUtilityUnitTest
15: {
16: private const string IV_AESCRYPTOSERVICEPROVIDER = @"xMHcVFe6M0cFuj2XwDxW4g==";
17: private const string KEY_AESCRYPTOSERVICEPROVIDER = @"2lrJwsLB3yejIqaxp5AHo+KFIzQnHbMG6bJB70L4bfo=";
18:
19: [TestMethod]
20: public void TestConfigurationUtility()
21: {
22: SymmetricCryptographyUtility crypt = new SymmetricCryptographyUtility(
23: SymmetricCryptographyTypeEnum.AesCryptoServiceProvider,
24: Convert.FromBase64String(IV_AESCRYPTOSERVICEPROVIDER),
25: Convert.FromBase64String(KEY_AESCRYPTOSERVICEPROVIDER));
26:
27: string configFileName = Path.Combine(
28: AppDomain.CurrentDomain.BaseDirectory,
29: @"CommonUtilityLibrary\Configuration\ConfigurationFile.xml");
30:
31: ConfigurationUtility config = new ConfigurationUtility(
32: configFileName,crypt);
33:
34: config.SetConfiguration("ConfigA", "Config A Value,配置A的值", false);
35: config.SetConfiguration("ConfigB", "Config B Value,配置B的加密值", true);
36:
37: Console.WriteLine(config.GetConfiguration("ConfigA"));
38: Console.WriteLine(config.GetConfiguration("ConfigB"));
39: }
40: }
41: }
测试结果如下:
配置文件的内容为:
1: <?xml version="1.0" encoding="utf-8"?>
2: <configurations>
3: <config key="ConfigA" value="Config A Value,配置A的值" isCrypt="False" />
4: <config key="ConfigB" value="78wPM5KLDQu534RLyhiZoZB3LwbJ8JF3uzl2Wttm+Uw43CgXyjDRmAUdG75SPnVZ" isCrypt="True" />
5: </configurations>
本文源代码下载:
https://files.cnblogs.com/DragonInSea/ExamSolution_04.rar
本文版权归作者所有,未经同意,请勿用作商业用途。