转自https://www.cnblogs.com/tonnie/archive/2010/12/17/appconfig.html

在一般的项目中,为了使你的代码更加灵活,更方便调整,减少不必要的hard code,我们都在config中添加许多配置信息,一般可以选择.NET自带的配置文件形式app.config或者web项目中的web.config来完成配置工作。
.NET中提供了几个和配置有关的类来支持用完轻松的完成配置文件的读写设置:
System.Configuration.ConfigurationSectionGroup
一般和你项目中使用的Assambly保持1:1的对应关系,这样划分使得结构相对清晰,权责明确。当然你可以不使用它,这样一旦你的Assambly在别的地方要被重用时,找出相应的config信息就变得很困难。
System.Configuration.ConfigurationSection
维护一个相对独立的配置节,使用时需现在<ConfigSections></ConfigSections>节点下声明。我们熟悉的<appSettings></appSettings>以及<connectionStrings></connectionStrings/>就是.NET为我们预留的一个Section。
System.Configuration.ConfigurationElementCollection & 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[elementChildB] = value; }
}
} public class CustomSectionWithChildElementBroker
{
private CustomSectionWithChildElement customSection = null;
public void InsertCustomSection()
{
customSection = new CustomSectionWithChildElement();
customSection.ChildSectionA = new CustomSectionElementA();
customSection.ChildSectionB= new CustomSectionElementB(); System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.Sections.Add("CustomSectionWithChildElement", customSection);
config.Save(ConfigurationSaveMode.Minimal);
} public int GetCustomSectionChildAID()
{
System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
CustomSectionWithChildElement cswe = config.GetSection("CustomSectionWithChildElement") as CustomSectionWithChildElement;
return cswe.ChildSectionA.ChildID;
}
}
红色字体就是修改的地方了,将Property改成我们自定义类的形式.测试代码如下:
[TestMethod]
public void TestCustomSectionWithChildElement()
{
CustomSectionWithChildElementBroker cweb = new CustomSectionWithChildElementBroker();
cweb.InsertCustomSection();
Assert.AreEqual(1, cweb.GetCustomSectionChildAID());
}

看看运行后我们的app.config变成什么样子了:

<configuration>
<configSections>
<section name="CustomSectionWithChildElement" type="Tonnie.Configuration.Library.CustomSectionWithChildElement, Tonnie.Configuration.Library, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<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>
<CustomSectionWithChildElement>
<childSectionA childId="1" childValue="ChildA" />
<childSectionB childId="2" childValue="ChildB" />
</CustomSectionWithChildElement>

<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>

cool,好像完成了我们的要求。

下面为我们的CustomSectionWithChildElement外面再加一层SectionGroup.

 public class CustomSectionGroup : System.Configuration.ConfigurationSectionGroup
{
[ConfigurationProperty("customSectionA", IsRequired = true, IsKey = true)]
public CustomSectionWithChildElement SectionA
{
get { return base.Sections["customSectionA"] as CustomSectionWithChildElement; }
set
{
this.Sections.Add("customSectionA", value);
}
}
}
 
 public class CustomSectionGroupWithChildElementBroker
{
private CustomSectionWithChildElement customSection = null;
public void InsertCustomSectionGroup()
{
customSection = new CustomSectionWithChildElement();
customSection.ChildSectionA = new CustomSectionElementA();
customSection.ChildSectionB= new CustomSectionElementB(); CustomSectionGroup sectionGroup = new CustomSectionGroup();
System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
if (config.GetSectionGroup("customSectionGroup") == null)
config.SectionGroups.Add("customSectionGroup",sectionGroup);
sectionGroup.SectionA = customSection;
config.Save(ConfigurationSaveMode.Minimal);
} public int GetCustomSectionChildAID()
{
System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); CustomSectionWithChildElement cswe = config.GetSection("customSectionGroup/customSectionA") as CustomSectionWithChildElement;
return cswe.ChildSectionA.ChildID;
}
}
测试一下:
  [TestMethod]
public void TestCustomSectionGroupWithChildElement()
{
CustomSectionGroupWithChildElementBroker cweb = new CustomSectionGroupWithChildElementBroker();
cweb.InsertCustomSectionGroup();
Assert.AreEqual(1, cweb.GetCustomSectionChildAID());
}
没问题,看下现在的app.config,是不是更加结构化了:
<configuration>
<configSections>
<sectionGroup name="MySectionGroup">
<section name="MyFirstSection" type="System.Configuration.DictionarySectionHandler"/>
<section name="MySecondSection" type="System.Configuration.DictionarySectionHandler"/>
</sectionGroup> <sectionGroup name="customSectionGroup" type="Tonnie.Configuration.Library.CustomSectionGroup, Tonnie.Configuration.Library, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" >
<section name="customSectionA" type="Tonnie.Configuration.Library.CustomSectionWithChildElement, Tonnie.Configuration.Library, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</sectionGroup>

</configSections>
<MySectionGroup>
<MyFirstSection>
<add key="First" value="First Section"/>
</MyFirstSection>
<MySecondSection>
<add key="Second" value="Second Section"/>
</MySecondSection>
</MySectionGroup>
<customSectionGroup>
<customSectionA>
<childSectionA childId="1" childValue="ChildA" />
<childSectionB childId="2" childValue="ChildB" />
</customSectionA>
</customSectionGroup>
</configuration>

3 高级玩法
 
到目前为止可能大家对app.config有了一定的认识了,我们自己可以不断的去扩展.NET Framework提供给我们的类,从SectionGroup,Section,ElementCollection,Element 从上自下的一级一级的组装成符合工程化项目配置文件需要的形式。当遇到可能配置元素的类型属性差不多时,可以抽象出一个base类来。比如可以抽象出Section这一层面的base类,或者ElementCollection,Element这一层的抽象类(可以是抽象的泛型类)来。同时增加泛型来更好的支持扩展。具体例子下次再给了。
 
附上所有代码:/Files/tonnie/Tonnie.Configuration.rar
一点点心得,欢迎交流……

一步一步教你玩转.NET Framework的配置文件app.config的更多相关文章

  1. 一步一步教你如何在linux下配置apache+tomcat(转)

    一步一步教你如何在linux下配置apache+tomcat   一.安装前准备. 1.   所有组件都安装到/usr/local/e789目录下 2.   解压缩命令:tar —vxzf 文件名(. ...

  2. 一步一步教你将普通的wifi路由器变为智能广告路由器

    一步一步教你将普通的wifi路由器变为智能广告路由器 相信大家对WiFi智能广告路由器已经不再陌生了,现在很多公共WiFi上网,都需要登录并且验证,这也就是WiFi广告路由器的最重要的功能.大致就是下 ...

  3. 一步一步教你使用Git

    一步一步教你使用Git 互联网给我们带来方便的同时,也时常让我们感到困惑.随便搜搜就出一大堆结果,然而总是有大量的重复和错误.小妖发出的内容,都是自己实测过的,有问题请留言. 现在,你已经安装了Git ...

  4. 使用WPF教你一步一步实现连连看

    使用WPF教你一步一步实现连连看(一) 第一步: 问题,怎样动态的建立一个10*10的grid(布局) for (int i = 0; i < 10; i++){ RowDefinition r ...

  5. 一步一步教你用 Vue.js + Vuex 制作专门收藏微信公众号的 app

    一步一步教你用 Vue.js + Vuex 制作专门收藏微信公众号的 app 转载 作者:jrainlau 链接:https://segmentfault.com/a/1190000005844155 ...

  6. Ace教你一步一步做Android新闻客户端(一)

    复制粘贴了那么多博文很不好意思没点自己原创的也说不出去,现在写一篇一步一步教你做安卓新闻客户端,借此机会也是让自己把相关的技术再复习一遍,大神莫笑,专门做给新手看. 手里存了两篇,一个包括软件视图 和 ...

  7. 一步一步教你实现iOS音频频谱动画(二)

    如果你想先看看最终效果再决定看不看文章 -> bilibili 示例代码下载 第一篇:一步一步教你实现iOS音频频谱动画(一) 本文是系列文章中的第二篇,上篇讲述了音频播放和频谱数据计算,本篇讲 ...

  8. 一步一步教你实现iOS音频频谱动画(一)

    如果你想先看看最终效果再决定看不看文章 -> bilibili 示例代码下载 第二篇:一步一步教你实现iOS音频频谱动画(二) 基于篇幅考虑,本次教程分为两篇文章,本篇文章主要讲述音频播放和频谱 ...

  9. 通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布

    之前的章节我们介绍了如何通过dapr发起一个服务调用,相信看过前几章的小伙伴已经对dapr有一个基本的了解了,今天我们来聊一聊dapr的另外一个功能--订阅发布 目录:一.通过Dapr实现一个简单的基 ...

随机推荐

  1. [Hadoop]&nbsp;Sqoop安装过程详解

    Sqoop是一个用来将Hadoop和关系型数据库中的数据相互转移的工具,可以将一个关系型数据库(例如 : MySQL ,Oracle ,Postgres等)中的数据导进到Hadoop的HDFS中,也可 ...

  2. 【机器学习】迭代决策树GBRT(渐进梯度回归树)

    一.决策树模型组合 单决策树C4.5由于功能太简单,并且非常容易出现过拟合的现象,于是引申出了许多变种决策树,就是将单决策树进行模型组合,形成多决策树,比较典型的就是迭代决策树GBRT和随机森林RF. ...

  3. linux 下jansson安装和使用

    1.安装jansson ./configure make make install 2.生成帮助文档 cd doc make html 编译安装doc时提示 spinx-build not a com ...

  4. maven工程导入eclipse后报错

    原因:需要重新部署下tomcat环境 解决方式: 右击->属性:

  5. go实现冒泡排序和快速排序

    项目结构 冒泡排序算法,源文件bubblesort.go package bubblesort // 冒泡排序 func BubbleSort(values []int) { for i := 0; ...

  6. 使用军哥的lnmp配置虚拟主机,需要注意的是要配置hosts文件

    #使用军哥的lnmp配置虚拟主机,需要注意的是要配置hosts文件(这一点官方没有讲到)具体方法:1.修改hosts文件sudo vim /etc/hosts 2.在hosts文件中新增一行(这里类似 ...

  7. 图像像素灰度内插(Matlab实现)

    常用的像素灰度内插法:最近邻元法.双线性内插法.三次内插法 %%像素灰度内插 factor = 0.75;%缩放比 u = 0.6;v = 0.7; itp1 = uint8(zeros(ceil(h ...

  8. Windows服务器初始配置

    系统状态是否良好 检查ip地址.子网掩码等配置 防火墙是否关闭 是否有攻击,有多大的攻击,什么类型的攻击,攻击流量图 是否中病毒 1.改端口 (1)打开注册表 [HKEY_LOCAL_MACHINE\ ...

  9. JavaWeb案例:上次访问时间 Cookie技术

    package cn.itcast.access; import javax.servlet.ServletException; import javax.servlet.annotation.Web ...

  10. Roslyn 编译器和RyuJIT 编译器

    Roslyn 编译器 https://msdn.microsoft.com/zh-cn/library/mt162308.aspx https://blogs.msdn.microsoft.com/d ...