.NET中提供了几个和配置有关的类来支持用完
轻松的完成配置文件的读写设置: System.Configuration.ConfigurationSectionGroup 一般和你项目中使用的Assambly保持1:1的对应关系,这样划分使得结构相对清晰,权责明确。当然你可以不使用它,这样一旦你的Assambly在别的地方要被重用时,找出相应的config信息就变得很困难。 System.Configuration.ConfigurationSection 维护一个相对独立的配置节,使用时需现在<ConfigSections></ConfigSections>节点下声明。我们熟悉的<appSettings></appSettings>以及<connectionStrings></connectionStrings/>就是.NET为我们预留的一个Section。 System.Configuration.ConfigurationElement
Collection & System.Configuration.ConfigurationElement 就是Section下具体的配置信息和配置信息的集合了。 下面
来看看怎么使用这些类玩转app.config 1.初级玩法 最初级的用法当然是使用<appSettings/>,我们在app.config 中添加:
<configuration>
<appSettings>
<add key="MyConfigString" value="Test Config Data"/>
</appSettings>
</configuration> 访问它:
public class AppSettingConfig
{
public string resultValue;
public AppSettingConfig()
{
this.resultValue = ConfigurationManager.AppSettings["MyConfigString"].ToString();
}
}
[TestMethod]
public void TestAppSettingConfigNode()
{
AppSettingConfig appCon = new AppSettingConfig();
Assert.AreEqual("Test Config Data", appCon.resultValue);
}
我们加个Section来看看如何访问:
<configuration>
<configSections>
<sectionGroup name="MySectionGroup">
<section name="MyFirstSection" type="System.Configuration.DictionarySectionHandler"/>
<section name="MySecondSection" type="System.Configuration.DictionarySectionHandler"/>
</sectionGroup>
</configSections>
<MySectionGroup>
<MyFirstSection>
<add key="First" value="First Section"/>
</MyFirstSection>
<MySecondSection>
<add key="Second" value="Second Section"/>
</MySecondSection>
</MySectionGroup>
</configuration>
注意我们在section的type中给出了System.Configuration.DictionarySectionHandler,这也限制了我们在具体的ConfigurationElement中只能使用<add key=”” value=””/>的形式,使得我们GetSection()方法返回的是一个IDictory对象,我们可以根据Key来取得相应的值:
public class SectionConfig
{
public string resultValue;
public SectionConfig()
{
System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
IDictionary dic = ConfigurationManager.GetSection("MySectionGroup/MySecondSection") as IDictionary;
this.resultValue = dic["Second"].ToString();
}
}
[TestMethod]
public void TestSectionGroupConfigNode()
{
SectionConfig sc = new SectionConfig();
Assert.AreEqual("First Section", sc.resultValue);
}
2. 中级玩法
.NET支持对上述提到的configuration类进行扩展,我们可以定义自己的Section。继承自基类System.Configuration.ConfigurationSection,ConfigurationSection已经提供了索引器用来获取设置数据。在类中加上ConfigurationProperty属性来定义Section中的Element:
public class CustomSection:System.Configuration.ConfigurationSection
{
[ConfigurationProperty("sectionId", IsRequired=true, IsKey=true)]
public int SectionId {
get { return (int)base["sectionId"]; }
set { base["sectionId"] = value; }
}
[ConfigurationProperty("sectionValue", IsRequired = false)]
public string SectionValue {
get { return base["sectionValue"].ToString(); }
set { base["sectionValue"] = value; }
}
}
操作此Section,我们将其动态加入app.config中,并读出来:
public class CustomSectionBroker
{
private CustomSection customSection = null;
public void InsertCustomSection()
{
customSection = new CustomSection();
customSection.SectionId = 1;
customSection.SectionValue = "The First Value";
System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.Sections.Add("CustomSection", customSection);
config.Save(ConfigurationSaveMode.Minimal);
}
public int GetCustomSectionID()
{
System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
CustomSection cs = config.GetSection("CustomSection") as CustomSection;
return cs.SectionId;
}
}
[TestMethod]
public void TestCustomSection()
{
CustomSectionBroker cb = new CustomSectionBroker();
cb.InsertCustomSection();
Assert.AreEqual(1, cb.GetCustomSectionID());
}
可以看下现在app.config文件的变化:
<configuration>
<configSections>
<section name="CustomSection" type="Tonnie.Configuration.
Library.CustomSection, Tonnie.Configuration.Library, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<sectionGroup name="MySectionGroup">
<section name="MyFirstSection" type="System.Configuration.DictionarySectionHandler"/>
<section name="MySecondSection" type="System.Configuration.DictionarySectionHandler"/>
</sectionGroup>
</configSections>
<CustomSection sectionId="1" sectionValue="The First Value" />
<MySectionGroup>
<MyFirstSection>
<add key="First" value="First Section"/>
</MyFirstSection>
<MySecondSection>
<add key="Second" value="Second Section"/>
</MySecondSection>
</MySectionGroup>
</configuration>
增加了一个单独的Section,名为"CustomSection",并且包含了我们创建的2个 configurationProperty。我们还可以继续作扩展,现在我们的config中section的部分呈现的是<CustomSection sectionId="1" sectionValue="The First Value" /> ,这样对于复杂的配置信息仍然不方便,我们是不是可以继续扩展,将其变成比较合理的:
<CustomSection>
<ChildCustomSectionA childId=1 childValue=”ChildA”></ChildCustomSectionA>
<ChildCustomSectionB childid=2 childValue=”ChildB”></ChildCustomSectionB>
</CustomSection>
这种方式呢? 我们为<ChildCustomSectionA></ChildCustomSectionA>创建扩展自ConfigurationElement类的子类CustomSectionElementA,然后修改CustomSection类中的Property,使得类型不再是int 或 string,而是我们创建的新类CustomSectionElementA。
由于ChildCustomSectionA 和ChildCustomSectionB 的结构相对一致,根据面向对象的开发封闭原则,我们可以先抽象出一个base类,然后让ChildCustomSectionA,ChildCustomSectionB分别继承自此base类,当以后要添加更多的ChildCustomSectionC,ChildCustomSectionD…时,使用这种Template的设计模式,将更加灵活。
public abstract class CustomSectionElementBase:System.Configuration.ConfigurationElement
{
[ConfigurationProperty("childId", IsRequired=true, IsKey=true)]
public int ChildID
{
get{return (int)base["childId"];}
set{base["childId"] = value;}
}
[ConfigurationProperty("childValue", IsRequired=true)]
public string ChildValue
{
get{return base["childValue"].ToString();}
set{base["childValue"] = value;}
}
}
public class CustomSectionElementA:CustomSectionElementBase
{
public CustomSectionElementA()
{
base.ChildID = 1;
base.ChildValue = "ChildA";
}
}
public class CustomSectionElementB:CustomSectionElementBase
{
public CustomSectionElementB()
{
base.ChildID = 2;
base.ChildValue = "ChildB";
}
}
完成了ConfigurationElement的实现,我们可以改写我们上一个例子中定义的CustomSection类了:
public class CustomSectionWithChildElement:System.Configuration.ConfigurationSection
{
private const string elementChildA = "childSectionA";
private const string elementChildB = "childSectionB";
[ConfigurationProperty(elementChildA, IsRequired=true, IsKey=true)]
public CustomSectionElementA ChildSectionA {
get { return base[elementChildA] as CustomSectionElementA; }
set { base[elementChildA] = value; }
}
[ConfigurationProperty(elementChildB, IsRequired = true)]
public CustomSectionElementB ChildSectionB {
get { return base[elementChildB] as CustomSectionElementB; }
set { base