您的位置:首页 > 移动开发

使用.NET Framework的配置文件app.config

2016-06-16 10:13 429 查看
在一般的项目中,为了使你的代码更加灵活,更方便调整,减少不必要的hardcode,我们都在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&[b]System.Configuration.ConfigurationElement[/b]
就是Section下具体的配置信息和配置信息的集合了。

下面来看看怎么使用这些类玩转app.config

1.初级使用

最初级的用法当然是使用<appSettings/>,我们在app.config中添加

<configuration>
<appSettings>
<addkey="MyConfigString"value="TestConfigData"/>
</appSettings>
</configuration>


访问它

  publicclassAppSettingConfig
{
publicstringresultValue;
publicAppSettingConfig()
{
this.resultValue=ConfigurationManager.AppSettings["MyConfigString"].ToString();
}
}
[TestMethod]
publicvoidTestAppSettingConfigNode()
{
AppSettingConfigappCon=newAppSettingConfig();
Assert.AreEqual("TestConfigData",appCon.resultValue);
}


没有问题!


我们加个Section来看看如何访问:


<configuration>
<configSections>
<sectionGroupname="MySectionGroup">
<sectionname="MyFirstSection"type="System.Configuration.DictionarySectionHandler"/>
<sectionname="MySecondSection"type="System.Configuration.DictionarySectionHandler"/>
</sectionGroup>

</configSections>
<MySectionGroup>
<MyFirstSection>
<addkey="First"value="FirstSection"/>
</MyFirstSection>
<MySecondSection>
<addkey="Second"value="SecondSection"/>
</MySecondSection>
</MySectionGroup>
</configuration>


注意我们在section的type中给出了System.Configuration.DictionarySectionHandler,这也限制了我们在具体的ConfigurationElement中只能使用<addkey=””value=””/>的形式,使得我们GetSection()方法返回的是一个IDictory对象,我们可以根据Key来取得相应的值



  publicclassSectionConfig
{
publicstringresultValue;
publicSectionConfig()
{
System.Configuration.Configurationconfig=ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

IDictionarydic=ConfigurationManager.GetSection("MySectionGroup/MySecondSection")asIDictionary;
this.resultValue=dic["Second"].ToString();

}
}
[TestMethod]
publicvoidTestSectionGroupConfigNode()
{
SectionConfigsc=newSectionConfig();
Assert.AreEqual("FirstSection",sc.resultValue);
}


还是没问题。


2.中级使用

.NET支持对上述提到的configuration类进行扩展,我们可以定义自己的Section。

继承自基类System.Configuration.ConfigurationSection,ConfigurationSection已经提供了索引器用来获取设置数据。

在类中加上ConfigurationProperty属性来定义Section中的Element:



 publicclassCustomSection:System.Configuration.ConfigurationSection
{
[ConfigurationProperty("sectionId",IsRequired=true,IsKey=true)]
publicintSectionId{
get{return(int)base["sectionId"];}
set{base["sectionId"]=value;}
}

[ConfigurationProperty("sectionValue",IsRequired=false)]
publicstringSectionValue{
get{returnbase["sectionValue"].ToString();}
set{base["sectionValue"]=value;}
}
}


操作此Section,我们将其动态加入app.config中,并读出来:


  publicclassCustomSectionBroker
{
privateCustomSectioncustomSection=null;
publicvoidInsertCustomSection()
{
customSection=newCustomSection();
customSection.SectionId=1;
customSection.SectionValue="TheFirstValue";
System.Configuration.Configurationconfig=ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.Sections.Add("CustomSection",customSection);
config.Save(ConfigurationSaveMode.Minimal);
}

publicintGetCustomSectionID()
{
System.Configuration.Configurationconfig=ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
CustomSectioncs=config.GetSection("CustomSection")asCustomSection;
returncs.SectionId;
}
}

  [TestMethod]
  publicvoidTestCustomSection()
  {
  CustomSectionBrokercb=newCustomSectionBroker();
  cb.InsertCustomSection();
  Assert.AreEqual(1,cb.GetCustomSectionID());
  }


可以看下现在app.config文件的变化:


<configuration>
<configSections>
<sectionname="CustomSection"type="Tonnie.Configuration.Library.CustomSection,Tonnie.Configuration.Library,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"/>
<sectionGroupname="MySectionGroup">
<sectionname="MyFirstSection"type="System.Configuration.DictionarySectionHandler"/>
<sectionname="MySecondSection"type="System.Configuration.DictionarySectionHandler"/>
</sectionGroup>

</configSections>
<CustomSectionsectionId="1"sectionValue="TheFirstValue"/>
<MySectionGroup>
<MyFirstSection>
<addkey="First"value="FirstSection"/>
</MyFirstSection>
<MySecondSection>
<addkey="Second"value="SecondSection"/>
</MySecondSection>
</MySectionGroup>
</configuration>


增加了一个单独的Section,名为"CustomSection",并且包含了我们创建的2个configurationProperty。
我们还可以继续作扩展,现在我们的config中section的部分呈现的是<CustomSectionsectionId="1"sectionValue="TheFirstValue"/>,这样对于复杂的配置信息仍然不方便,我们是不是可以继续扩展,将其变成比较合理的
<CustomSection>
<ChildCustomSectionAchildId=1childValue=”ChildA”></ChildCustomSectionA>
<ChildCustomSectionBchildid=2childValue=”ChildB”></ChildCustomSectionB>
</CustomSection>
这种方式呢?我们为<ChildCustomSectionA></ChildCustomSectionA>创建扩展自ConfigurationElement类的子类CustomSectionElementA,然后修改CustomSection类中的Property,使得类型不再是int或string,而是我们创建的新类CustomSectionElementA.
由于ChildCustomSectionA和ChildCustomSectionB的结构相对一致,根据面向对象的开发封闭原则,我们可以先抽象出一个base类,然后让ChildCustomSectionA,ChildCustomSectionB分别继承自此base类,当以后要添加更多的ChildCustomSectionC,ChildCustomSectionD…时,使用这种Template的设计模式,将更加灵活。

  publicabstractclassCustomSectionElementBase:System.Configuration.ConfigurationElement
{
[ConfigurationProperty("childId",IsRequired=true,IsKey=true)]
publicintChildID
{
get{return(int)base["childId"];}
set{base["childId"]=value;}
}

[ConfigurationProperty("childValue",IsRequired=true)]
publicstringChildValue
{
get{returnbase["childValue"].ToString();}
set{base["childValue"]=value;}
}
}

publicclassCustomSectionElementA:CustomSectionElementBase
{
publicCustomSectionElementA()
{
base.ChildID=1;
base.ChildValue="ChildA";
}
}
publicclassCustomSectionElementB:CustomSectionElementBase
{
publicCustomSectionElementB()
{
base.ChildID=2;
base.ChildValue="ChildB";
}
}


完成了ConfigurationElement的实现,我们可以改写我们上一个例子中定义的CustomSection类了:

  publicclassCustomSectionWithChildElement:System.Configuration.ConfigurationSection
{
privateconststringelementChildA="childSectionA";
privateconststringelementChildB="childSectionB";

[ConfigurationProperty(elementChildA,IsRequired=true,IsKey=true)]
publicCustomSectionElementAChildSectionA{
get{returnbase[elementChildA]asCustomSectionElementA;}
set{base[elementChildA]=value;}
}

[ConfigurationProperty(elementChildB,IsRequired=true)]
publicCustomSectionElementBChildSectionB{
get{returnbase[elementChildB]asCustomSectionElementB;}
set{base[elementChildB]=value;}
}
}

publicclassCustomSectionWithChildElementBroker
{
privateCustomSectionWithChildElementcustomSection=null;
publicvoidInsertCustomSection()
{
customSection=newCustomSectionWithChildElement();
customSection.ChildSectionA=newCustomSectionElementA();
customSection.ChildSectionB=newCustomSectionElementB();

System.Configuration.Configurationconfig=ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.Sections.Add("CustomSectionWithChildElement",customSection);
config.Save(ConfigurationSaveMode.Minimal);
}

publicintGetCustomSectionChildAID()
{
System.Configuration.Configurationconfig=ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
CustomSectionWithChildElementcswe=config.GetSection("CustomSectionWithChildElement")asCustomSectionWithChildElement;
returncswe.ChildSectionA.ChildID;
}
}


红色字体就是修改的地方了,将Property改成我们自定义类的形式.测试代码如下:


    [TestMethod]
publicvoidTestCustomSectionWithChildElement()
{
CustomSectionWithChildElementBrokercweb=newCustomSectionWithChildElementBroker();
cweb.InsertCustomSection();
Assert.AreEqual(1,cweb.GetCustomSectionChildAID());
}


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

<configuration>
<configSections>
<sectionname="CustomSectionWithChildElement"type="Tonnie.Configuration.Library.CustomSectionWithChildElement,Tonnie.Configuration.Library,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"/>
<sectionname="CustomSection"type="Tonnie.Configuration.Library.CustomSection,Tonnie.Configuration.Library,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"/>
<sectionGroupname="MySectionGroup">
<sectionname="MyFirstSection"type="System.Configuration.DictionarySectionHandler"/>
<sectionname="MySecondSection"type="System.Configuration.DictionarySectionHandler"/>
</sectionGroup>

</configSections>
<CustomSectionWithChildElement>
<childSectionAchildId="1"childValue="ChildA"/>
<childSectionBchildId="2"childValue="ChildB"/>
</CustomSectionWithChildElement>
<CustomSectionsectionId="1"sectionValue="TheFirstValue"/>
<MySectionGroup>
<MyFirstSection>
<addkey="First"value="FirstSection"/>
</MyFirstSection>
<MySecondSection>
<addkey="Second"value="SecondSection"/>
</MySecondSection>
</MySectionGroup>
</configuration>


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

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

  publicclassCustomSectionGroup:System.Configuration.ConfigurationSectionGroup
{
[ConfigurationProperty("customSectionA",IsRequired=true,IsKey=true)]
publicCustomSectionWithChildElementSectionA
{
get{returnbase.Sections["customSectionA"]asCustomSectionWithChildElement;}
set
{
this.Sections.Add("customSectionA",value);
}
}
}

  publicclassCustomSectionGroupWithChildElementBroker
{
privateCustomSectionWithChildElementcustomSection=null;
publicvoidInsertCustomSectionGroup()
{
customSection=newCustomSectionWithChildElement();
customSection.ChildSectionA=newCustomSectionElementA();
customSection.ChildSectionB=newCustomSectionElementB();

CustomSectionGroupsectionGroup=newCustomSectionGroup();
System.Configuration.Configurationconfig=ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
if(config.GetSectionGroup("customSectionGroup")==null)
config.SectionGroups.Add("customSectionGroup",sectionGroup);
sectionGroup.SectionA=customSection;
config.Save(ConfigurationSaveMode.Minimal);
}

publicintGetCustomSectionChildAID()
{
System.Configuration.Configurationconfig=ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

CustomSectionWithChildElementcswe=config.GetSection("customSectionGroup/customSectionA")asCustomSectionWithChildElement;
returncswe.ChildSectionA.ChildID;
}
}


测试一下:


    [TestMethod]
publicvoidTestCustomSectionGroupWithChildElement()
{
CustomSectionGroupWithChildElementBrokercweb=newCustomSectionGroupWithChildElementBroker();
cweb.InsertCustomSectionGroup();
Assert.AreEqual(1,cweb.GetCustomSectionChildAID());
}


没问题,看下现在的app.config,是不是更加结构化了:


<configuration>
<configSections>
<sectionGroupname="MySectionGroup">
<sectionname="MyFirstSection"type="System.Configuration.DictionarySectionHandler"/>
<sectionname="MySecondSection"type="System.Configuration.DictionarySectionHandler"/>
</sectionGroup>

<sectionGroupname="customSectionGroup"type="Tonnie.Configuration.Library.CustomSectionGroup,Tonnie.Configuration.Library,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null">
<sectionname="customSectionA"type="Tonnie.Configuration.Library.CustomSectionWithChildElement,Tonnie.Configuration.Library,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"/>
</sectionGroup>
</configSections>
<MySectionGroup>
<MyFirstSection>
<addkey="First"value="FirstSection"/>
</MyFirstSection>
<MySecondSection>
<addkey="Second"value="SecondSection"/>
</MySecondSection>
</MySectionGroup>
<customSectionGroup>
<customSectionA>
<childSectionAchildId="1"childValue="ChildA"/>
<childSectionBchildId="2"childValue="ChildB"/>
</customSectionA>
</customSectionGroup>
</configuration>


3高级使用

到目前为止可能大家对app.config有了一定的认识了,我们自己可以不断的去扩展.NETFramework提供给我们的类,从SectionGroup,Section,ElementCollection,Element从上自下的一级一级的组装成符合工程化项目配置文件需要的形式。当遇到可能配置元素的类型属性差不多时,可以抽象出一个base类来。比如可以抽象出Section这一层面的base类,或者ElementCollection,Element这一层的抽象类(可以是抽象的泛型类)来。同时增加泛型来更好的支持扩展。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: