《企业考试系统》项目实践(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: }

其类型成员及说明如下:

1

  • 构造方法:两个参数,一个表示配置文件的文件名,另一个为配置文件需要加密时使用的加密工具类
  • 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: }

测试结果如下:

2

配置文件的内容为:

   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

 

《企业考试系统》项目实践索引页:http://www.cnblogs.com/DragonInSea/archive/2010/06/02/1749762.html
posted @ 2010-06-07 10:50  龙腾于海  阅读(2340)  评论(7编辑  收藏  举报