.Net 自定义应用程序配置二(参照张子阳博客)
除了实现IConfigurationSectionHandler接口来自定义结点处理程序,还可以通过继承ConfigurationSection基类的方式来完成,我们还以上面的例子来做说明。一般来说我们想要存储的数据可以用两种方式来存储:一种是存储到结点的属性中,一种是存储在结点的文本(InnerText)中。比如:
<node>这里是要存储的值</node>
<!-- 或者是下面这样,两种的效果是一样的 -->
<node text="这里是要存储的值" />
因为一个结点可以有很多的属性,但只有一个InnerText,而在程序又要将这两种形式区别处理显然太麻烦了,所以Microsoft干脆就只使用属性存储而不使用InnerText,大家可以看一下machine.config中的配置,可曾见到过一个以InnerText来存储配置信息的?在ConfigurationSection中,也没有提供对InnerText的处理,所以对于上面的例子,我们首先要进行重新格式化,仅使用属性来存储我们的配置值。
除此以外,我们还要将结点分组,对于入口结点,也就是mailServerGroup而言,这个结点组相当于它的一个属性(就好像provider一样),因为结点组包含多个结点,所以映射到面向对象的代码中,自然就成了一个集合类。所以我们需要按照这些概念将web.config中的mailServerGroup改写成下面这样:
<mailServerGroup2 provider="www.edong.com">
<mailServers>
<mailServer
client="forum.tracefact.net"
address="mail1.tracefact.net"
userName="jimmyzhang"
password="123456" />
<mailServer
client="blog.tracefact.net"
address="mail2.tracefact.net"
userName="webmaster"
password="456789" />
</mailServers>
</mailServerGroup2>
注意,我们将mailServerGroup改成了mailServerGroup2,以免和上一节的冲突。现在我们在CustomConfig项目中添加一个文件 MailServerSection.cs,然后添加如下代码:
// MailServerSection 为入口
public class MailServerSection : ConfigurationSection {
[ConfigurationProperty("provider", IsKey = true)]
public string Provider {
get { return this["provider"] as string; }
}
[ConfigurationProperty("mailServers", IsDefaultCollection = false)]
public MailServerCollection MailServers {
get {
return (MailServerCollection)this["mailServers"];
}
set {
this["mailServers"] = value;
}
}
}
// MailServer 结点和集合类
public sealed class MailServerElement : ConfigurationElement {
[ConfigurationProperty("client", IsKey = true, IsRequired = true)]
public string Client {
get { return this["client"] as string; }
set { this["client"] = value; }
}
[ConfigurationProperty("address")]
public string Address {
get { return this["address"] as string; }
set { this["client"] = value; }
}
[ConfigurationProperty("userName")]
public string UserName {
get { return this["userName"] as string; }
set { this["client"] = value; }
}
[ConfigurationProperty("password")]
public string Password {
get { return this["password"] as string; }
set { this["client"] = value; }
}
}
// MailServer 集合类
public sealed class MailServerCollection : ConfigurationElementCollection {
public override ConfigurationElementCollectionType CollectionType {
get { return ConfigurationElementCollectionType.BasicMap; }
}
protected override ConfigurationElement CreateNewElement() {
return new MailServerElement();
}
protected override Object GetElementKey(ConfigurationElement element) {
return ((MailServerElement)element).Client;
}
protected override string ElementName {
get { return "mailServer"; }
}
public new int Count {
get { return base.Count; }
}
public MailServerElement this[int index] {
get {
return (MailServerElement)BaseGet(index);
}
set {
if (BaseGet(index) != null) {
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
new public MailServerElement this[string Name] {
get {
return (MailServerElement)BaseGet(Name);
}
}
public int IndexOf(MailServerElement element) {
return BaseIndexOf(element);
}
public void Add(MailServerElement element) {
BaseAdd(element);
}
public void Remove(MailServerElement element) {
if (BaseIndexOf(element) >= 0)
BaseRemove(element.Client);
}
public void RemoveAt(int index) {
BaseRemoveAt(index);
}
public void Remove(string client) {
BaseRemove(client);
}
public void Clear() {
BaseClear();
}
}
这段代码由三部分组成,一部分是MailServerSection类,很明显它是配置结点的入口,它包含两个属性,一个是String类型的provider属性,它映射mailServerGroup结点的provider属性;一个是MailServerCollection类型的MailServers属性,这个属性映射我们新添加的mailServers结点,mailServers结点下还包含了若干个mailServer结点。从它的名称也可以看出来,它是一个集合类。
MailServerElement类用于映射mailServer结点的属性,这里是我们实际存储数据的地方。MailServerCollection类用于映射mailServers结点,可以看出它是一个集合类,另外还包含了很多对于结点进行操作的方法,大部分的能力都继承自ConfigurationElementCollection基类。
值得注意的是,之所以可以使用这种方式实现,使用了大量的特性标记。当你看到特性标记的时候,你应该就想到必须有地方使用反射来读取特性的值,不然特性毫无意义。只是这部分的内容属于.Net Framework的底层,无需我们操心。
原文链接:http://www.tracefact.net/CLR-and-Framework/Custom-Application-Configuration.aspx