65.9K
CodeProject 正在变化。 阅读更多。
Home

一个简单的二维配置文件

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.63/5 (9投票s)

2004年12月10日

4分钟阅读

viewsIcon

39830

本文介绍了一个简单的配置数据管理器。

引言

.NET 中的基于 XML 的配置文件是用于设置应用程序在运行时获取的常量的有用占位符。这些常量包括,例如,安全性设置、数据库连接字符串或其他应用程序特定数据。使用这些文件的主要优点之一是子 web.config 文件会覆盖其父文件,最顶层的父文件是位于 c:/WINNT/Microsoft.NET/Framework/v1.1.4322/CONFIG 目录中的 machine.config

虽然 web.configapp.config(Windows 应用程序的等效文件)在运行时提供标准系统相关值(例如,与程序集、处理程序、跟踪等相关的信息)很有用,但它们不适合存储应用程序数据,特别是当您想跨应用程序共享常量时。例如,不同类型的应用程序(例如,ASP.NET、Windows Forms、控制台应用程序等)会使用数据库连接字符串。您理想情况下希望只在一个地方更新每个值,而不是修改多个文件,这会给维护带来噩梦。

在 .NET 中,我能想到两种无需额外代码即可解决此问题的方法

  1. appSettings 键添加到 machine.config 文件,由于 machine.config 是最顶层的配置文件,该文件会自动确保计算机上的所有应用程序都可以访问它。
    <appSettings>
      <add key="myKey" value="myValue" />
    </appSettings>
  2. 通过指定一个文件来保存应用程序设置。这可以通过指定包含应用程序配置设置的外部文件的相对路径来完成。以下代码片段显示了 web.config 中的相关部分
    <configuration>
      <appSettings file="mySettings.config">
      </appSettings>
    </configuration>

    其中“mySettings.config”是一个自定义配置文件,看起来类似这样

    <appSettings>
      <add key="key1" value="value1" />
      <add key="key2" value="value2" />
      .....
    </appSettings>

第一种方法的缺点是,对于真正属于应用程序性质的事物,machine.config 文件比较危险。如果您不小心犯了错误,可能会危及服务器及其上的所有站点。此外,.NET 的未来版本可能会覆盖此文件并更改您所有设置,从而导致应用程序停止运行。

第二种方法稍好一些,因为您可以将所有应用程序或共享配置数据的应用程序指向同一个文件。这样做可以,因为您可以像这样访问任何值

String key1 = System.Configuration.ConfigurationSettings.AppSettings["key1"];

缺点是,查看设置文件时,如果没有适当的命名约定,您将不知道哪个值与哪个项目相关联。换句话说,该文件提供键/值对的平面(一维)表示,最多可能看起来像这样

<appSettings>
  <add key="p1key1" value="value1" />
  <add key="p1key2" value="value2" /> 
  <add key="p2key1" value="value1" />
  <add key="p2key2" value="value2" /> 
  <add key="p2key3" value="value1" />
  ....
</appSettings>

其中 p1 是项目 1,p2 是项目 2,依此类推。

这比操作 machine.config 要好,但维护起来很困难,尤其是在应用程序常量激增时。它也是一个必须强制执行于开发团队的约定。

这个问题有各种解决方案。我知道的一种叫做“配置应用程序块”,可以在这里找到。老实说,我认为这对于这个问题来说有点过度。在接下来的部分,我将介绍一种解决此问题的简单方法。

使用代码

基本上,我希望有一个二维的 web.config 文件,它看起来像这样

<configuration xmlns="http://tempuri.org/projects.xsd">
  <project>
    <projectName>Project1</projectName>
    <projectSettings>
      <add key="key1" value="cat" />
      <add key="key2" value="dog" />
    </projectSettings>
  </project>
  <project>
    <projectName>Project2</projectName>
    <projectSettings>
      <add key="key1" value="horse" />    
      <add key="key2" value="donkey" /> 
      <add key="key3" value="elephant" /> 
    </projectSettings>
  </project>
</configuration>

二维的意思是,第一个维度是项目名称,第二个维度是键。所以要获取值“dog”,您将访问 (project1, key2),要访问值“elephant”,您将访问 (project2, key3)。处理此问题的 C# 代码是

using System;
using System.IO;  
using System.Xml; 
using System.Configuration;
using System.Collections.Specialized;

namespace configUtils
{
  public sealed class configReader
  {
    const string projectsConfigPath = "c:/projects.config";
    
    public static NameValueCollection ProjectSettings 
    {
      get
        {
          NameValueCollection a = new NameValueCollection();
          XmlDocument xmlDoc = new XmlDocument();
          xmlDoc.Load(projectsConfigPath);
          XmlNode xmlRootNode =
            (xmlDoc.GetElementsByTagName("configuration"))[0];
          XmlNodeList xmlProjectNodes = xmlRootNode.ChildNodes;
          
          foreach (XmlNode xmlProjectNode in xmlProjectNodes)
            {
              string projectName = xmlProjectNode.ChildNodes[0].InnerText;
              XmlNodeList projectSettingNodes =
                xmlProjectNode.ChildNodes[1].ChildNodes;
              
              foreach (XmlNode projectSettingNode in projectSettingNodes)
                {
                  XmlAttributeCollection attributes =
                    projectSettingNode.Attributes;
                  XmlAttribute key = (XmlAttribute)
                    attributes.GetNamedItem("key");
                  XmlAttribute value = (XmlAttribute)
                    attributes.GetNamedItem("value");
                  string k = projectName + "," + key.Value;
                  string v = value.Value;
                  
                  a.Add(k, v);
                }
            }
          
          return a;          
        }
    }
  }
}

其中您的项目数据位于 c:/project.config

要访问值“elephant”,您的 C# 代码将执行

string animalName = configReader.ProjectSettings["Project2,key3"];

这是一行代码,您无需实例化对象即可使用,而且实现起来非常简单。当然,为了使此代码正常工作,您还需要在文件中添加一个 using 语句。

using configUtils;

这只是一个说明概念的简陋版本,不包含异常处理和其他辅助例程。

如上面的代码所示,我正在使用 NameValueCollection 类将单个参数“拆分”为项目和键值。另外,请注意,没有内容被硬编码到任何特定的 XML 标记(例如,“project”标记),并且集合的通用构造会生成返回值。在 project.config 文件中添加项目和键/值对无需任何代码更改或重新编译。

我想到了几种增强此代码的方法,并欢迎任何建议

  1. 使返回值看起来像
    string animalName = 
        configReader.ProjectSettings["Project2"]["key3"];

    以真正二维的方式。

  2. 某种缓存机制,以便在每次获取值时都不会重新构建集合。我非常确定编译器足够智能会缓存它,但认为显式代码可以确保正确缓存。

历史

  • 创建于 2004 年 12 月 10 日。
© . All rights reserved.