【.net 深呼吸】在配置节中使用元素集合
前一篇博文中,老周介绍了自定义配置节的方法,本文咱们再往深一层,再看看如何在自定义的配置节中使用配置元素集合。
前面咱们说过,Configuration Section是特殊的配置元素,它可以包装一类功能,并且在使用前,必须在配置文件中注册其类型。只有作为配置节的元素才需要从 ConfigurationSection 类派生,而对配置节下面的普通配置元素,只需要从 ConfigurationElement 类派生即可。
要在配置中使用元素集合,必须实现 ConfigurationElementCollection 抽象类,并实现或覆写需要的成员。其中,有两个抽象方法你必须要实现的:
1、CreateNewElement:返回集合中所包含的配置元素的实例,ConfigurationElement是公共基类,而实际要返回的是你自己定义的配置元素的实例。
2、GetElementKey:实现该方法,你可以按照你的思维,返回一个对象实例,作为集合中某个元素的标识,该返回值用来管理集合中的元素,当要检索元素时,就是通过这个返回的key来查找的。
在自定义的配置节类(从 ConfigurationSection 类派生的类)中,通过一个属性来公开集合对象(集合对象须实现 ConfigurationElementCollection 类),此属性的声明方法与上一篇文章中所讲述的配置属性定义一样。
好了,依老周一惯作风,下面给各位上一个实例。
先简单介绍一下我写的这个配置节,它公开一个 servers 属性,该属性是一个集合,每个集合中的元素可以单独配置服务器信息,host 表示服务主机名,port 表示服务器开放的端口号。
第一步要实殃一个普通元素,用来配置单条服务器信息,包括主机名和端口号。
public class SvItem : ConfigurationElement { [ConfigurationProperty("host", DefaultValue = "localhost")] public string Hostname { get { return (string)this["host"]; } set { this["host"] = value; } } [ConfigurationProperty("port", DefaultValue = "250")] public int Port { get { return (int)this["port"]; } set { this["port"] = value; } } }
注意,上一篇烂文中讲过的,ConfigurationPropertyAttribute 不要忘了,而且名字要与类索引器中的参数相同。这是个很普通很平凡很卑微的配置元素,所以从 ConfigurationElement 类派生即可。
接着,需要实现我们自定义的配置元素集合类。
public class SvitemCollection : ConfigurationElementCollection { protected override ConfigurationElement CreateNewElement() { return new SvItem(); } protected override object GetElementKey(ConfigurationElement element) { SvItem e = (SvItem)element; return e.Hostname; } public override ConfigurationElementCollectionType CollectionType => ConfigurationElementCollectionType.AddRemoveClearMap; public void Add(SvItem item) { string key = item.Hostname; if(BaseGet(key)!= null) { BaseRemove(key); } BaseAdd(item); } public void Remove(string host) { BaseRemove(host); } public SvItem Get(string host) { return (BaseGet(host) as SvItem); } }
自定义的配置集合类,当然要以 ConfigurationElementCollection 为基类。这个集合中的每个项,就是咱们上面刚定义的 SvItem 类,所以,在实现 CreateNewElement 方法时,直接返回一个新的对象实例即可。
GetElementKey 方法返回一个标识,作为某个项在集合中的key,这里我就用它的 Hostname属性作为key吧。
为了便于在类的外部操作,我公开了几个方法:
Add:向集合中添加元素,实现时可以调用基类的 BaseAdd 方法。
Remove:从集合中删除某元素。参数是作为元素key的Hostname属性值。
Get:根据Hostname属性的值获取元素实例。
根据实际需要,你可以自己编写更多的成员,比如按索引查找元素等。
接着,我们就要来写配置节了。
public class CustServs: ConfigurationSection { [ConfigurationProperty("servers", IsDefaultCollection = true)] public SvitemCollection Servers { get { return (SvitemCollection)this["servers"]; } } }
集合属性一般不需要赋值,而只是向其中添加元素,所以属性只有 get 访问器,没有编写 set 访问器。应用 ConfigurationProperty 特性时,设置了 IsDefaultCollection 属性为 true ,表示将使用默认的元素管理行为,即用 add 元素来添加,用remove元素来删除,用 clear 元素来清空集合。
刚刚上面定义 SvitemCollection 集合时,我重写了 CollectionType 属性。
public override ConfigurationElementCollectionType CollectionType => ConfigurationElementCollectionType.AddRemoveClearMap;
如此这个集合就支持 add、remove、clear 三种操作。
下面,咱们来试试用,在代码中进行好配置后,保存到 app.config 文件中。
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); CustServs sect = config.GetSection("custserver") as CustServs; if(sect == null) { sect = new CustServs(); config.Sections.Add("custserver", sect); } SvItem item1 = new SvItem { Hostname = "CholPC", Port = 3255 }; SvItem item2 = new SvItem { Hostname = "JobPC", Port = 2500 }; SvItem item3 = new SvItem { Hostname = "TomPC", Port = 566 }; sect.Servers.Add(item1); sect.Servers.Add(item2); sect.Servers.Add(item3); config.Save(ConfigurationSaveMode.Modified);
执行上面代码后,打开与应用程序同一目录下的 app.config 文件,就会看到生成这样的配置。
<configuration> <configSections> <section name="custserver" type="MyApp.CustServs, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </configSections> <custserver> <servers> <add host="CholPC" port="3255" /> <add host="JobPC" port="2500" /> <add host="TomPC" port="566" /> </servers> </custserver> …… </configuration>
默认集合的行为是用add元素来添加项的。
然后,我们把刚刚 Servers 属性的代码改一下。
public class CustServs: ConfigurationSection { [ConfigurationProperty("servers", IsDefaultCollection = false)] [ConfigurationCollection(typeof(SvitemCollection), AddItemName = "server", RemoveItemName = "del", ClearItemsName = "clr")] public SvitemCollection Servers { get { return (SvitemCollection)this["servers"]; } } }
首先可以把 IsDefaultCollection 改为 false,接着应用 ConfigurationCollection 特性,注意传递给构造函数的 type 是我们定义的集合类的type。AddItemName、RemoveItemName、ClearItemsName 这三个属性是用于替换 add、remove、clear 这几个默认名。
修改后,再次执行代码,生成的配置文件如下。
<configuration> <configSections> <section name="custserver" type="MyApp.CustServs, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </configSections> <custserver> <servers> <server host="CholPC" port="3255" /> <server host="JobPC" port="2500" /> <server host="TomPC" port="566" /> </servers> </custserver> …… </configuration>
这时候,你也发现了,向配置集合添加元素,不再使用 add 了,而是变为 server 了。
当然了,除了在代码中配置,你也可以直接在配置文件中设置,然后在代码中读取,这个与上一篇文章中所述的一样。
好了,该开饭了,本文内容就到此完结。