实现代码如下:
{
[ConfigurationProperty("Command1", IsRequired = true)]
public MyTextElement Command1
{
get { return (MyTextElement)this["Command1"]; }
}
[ConfigurationProperty("Command2", IsRequired = true)]
public MyTextElement Command2
{
get { return (MyTextElement)this["Command2"]; }
}
}
public class MyTextElement : ConfigurationElement
{
protected override void DeserializeElement(System.Xml.XmlReader reader, bool serializeCollectionKey)
{
CommandText = reader.ReadElementContentAs(typeof(string), null) as string;
}
protected override bool SerializeElement(System.Xml.XmlWriter writer, bool serializeCollectionKey)
{
if( writer != null )
writer.WriteCData(CommandText);
return true;
}
[ConfigurationProperty("data", IsRequired = false)]
public string CommandText
{
get { return this["data"].ToString(); }
set { this["data"] = value; }
}
}
小结:
1. 在实现上大体可参考MySection2,
2. 每个ConfigurationElement由我们来控制如何读写XML,也就是要重载方法SerializeElement,DeserializeElement
config文件 - Collection
<add key="aa" value="11111"></add>
<add key="bb" value="22222"></add>
<add key="cc" value="33333"></add>
</MySection444>
这种类似的配置方式,在ASP.NET的HttpHandler, HttpModule中太常见了,想不想知道如何实现它们? 代码如下:
{
private static readonly ConfigurationProperty s_property
= new ConfigurationProperty(string.Empty, typeof(MyKeyValueCollection), null,
ConfigurationPropertyOptions.IsDefaultCollection);
[ConfigurationProperty("", Options = ConfigurationPropertyOptions.IsDefaultCollection)]
public MyKeyValueCollection KeyValues
{
get
{
return (MyKeyValueCollection)base[s_property];
}
}
}
[ConfigurationCollection(typeof(MyKeyValueSetting))]
public class MyKeyValueCollection : ConfigurationElementCollection // 自定义一个集合
{
// 基本上,所有的方法都只要简单地调用基类的实现就可以了。
public MyKeyValueCollection() : base(StringComparer.OrdinalIgnoreCase) // 忽略大小写
{
}
// 其实关键就是这个索引器。但它也是调用基类的实现,只是做下类型转就行了。
new public MyKeyValueSetting this[string name]
{
get
{
return (MyKeyValueSetting)base.BaseGet(name);
}
}
// 下面二个方法中抽象类中必须要实现的。
protected override ConfigurationElement CreateNewElement()
{
return new MyKeyValueSetting();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((MyKeyValueSetting)element).Key;
}
// 说明:如果不需要在代码中修改集合,可以不实现Add, Clear, Remove
public void Add(MyKeyValueSetting setting)
{
this.BaseAdd(setting);
}
public void Clear()
{
base.BaseClear();
}
public void Remove(string name)
{
base.BaseRemove(name);
}
}
public class MyKeyValueSetting : ConfigurationElement // 集合中的每个元素
{
[ConfigurationProperty("key", IsRequired = true)]
public string Key
{
get { return this["key"].ToString(); }
set { this["key"] = value; }
}
[ConfigurationProperty("value", IsRequired = true)]
public string Value
{
get { return this["value"].ToString(); }
set { this["value"] = value; }
}
}
小结:
1. 为每个集合中的参数项创建一个从ConfigurationElement继承的派生类,可参考MySection1
2. 为集合创建一个从ConfigurationElementCollection继承的集合类,具体在实现时主要就是调用基类的方法。
3. 在创建ConfigurationSection的继承类时,创建一个表示集合的属性就可以了,注意[ConfigurationProperty]的各参数。
config文件 - 读与写
前面我逐个介绍了4种自定义的配置节点的实现类,下面再来看一下如何读写它们。
读取配置参数:
txtUsername1.Text = mySectioin1.UserName;
txtUrl1.Text = mySectioin1.Url;
MySection2 mySectioin2 = (MySection2)ConfigurationManager.GetSection("MySection222");
txtUsername2.Text = mySectioin2.Users.UserName;
txtUrl2.Text = mySectioin2.Users.Password;
MySection3 mySection3 = (MySection3)ConfigurationManager.GetSection("MySection333");
txtCommand1.Text = mySection3.Command1.CommandText.Trim();
txtCommand2.Text = mySection3.Command2.CommandText.Trim();
MySection4 mySection4 = (MySection4)ConfigurationManager.GetSection("MySection444");
txtKeyValues.Text = string.Join("\r\n",
(from kv in mySection4.KeyValues.Cast()
let s = string.Format("{0}={1}", kv.Key, kv.Value)
select s).ToArray());
小结:在读取自定节点时,我们需要调用ConfigurationManager.GetSection()得到配置节点,并转换成我们定义的配置节点类,然后就可以按照强类型的方式来访问了。
写配置文件:
MySection1 mySectioin1 = config.GetSection("MySection111") as MySection1;
mySectioin1.UserName = txtUsername1.Text.Trim();
mySectioin1.Url = txtUrl1.Text.Trim();
MySection2 mySection2 = config.GetSection("MySection222") as MySection2;
mySection2.Users.UserName = txtUsername2.Text.Trim();
mySection2.Users.Password = txtUrl2.Text.Trim();
MySection3 mySection3 = config.GetSection("MySection333") as MySection3;
mySection3.Command1.CommandText = txtCommand1.Text.Trim();
mySection3.Command2.CommandText = txtCommand2.Text.Trim();
MySection4 mySection4 = config.GetSection("MySection444") as MySection4;
mySection4.KeyValues.Clear();
(from s in txtKeyValues.Lines
let p = s.IndexOf('=')
where p > 0
select new MyKeyValueSetting { Key = s.Substring(0, p), Value = s.Substring(p + 1) }
).ToList()
.ForEach(kv => mySection4.KeyValues.Add(kv));
config.Save();
小结:在修改配置节点前,我们需要调用ConfigurationManager.OpenExeConfiguration(),然后调用config.GetSection()在得到节点后,转成我们定义的节点类型, 然后就可以按照强类型的方式来修改我们定义的各参数项,最后调用config.Save();即可。
注意:
1. .net为了优化配置节点的读取操作,会将数据缓存起来,如果希望使用修改后的结果生效,您还需要调用ConfigurationManager.RefreshSection(".....")
2. 如果是修改web.config,则需要使用 WebConfigurationManager
读写 .net framework中已经定义的节点
前面一直在演示自定义的节点,那么如何读取.net framework中已经定义的节点呢?
假如我想读取下面配置节点中的发件人。
<mailSettings>
<smtp from="Fish.Q.Li@newegg.com">
<network />
</smtp>
</mailSettings>
</system.net>
读取配置参数:
labMailFrom.Text = "Mail From: " + section.From;
写配置文件:
SmtpSection section = config.GetSection("system.net/mailSettings/smtp") as SmtpSection;
section.From = "Fish.Q.Li@newegg.com2";
config.Save();
xml配置文件
前面演示在config文件中创建自定义配置节点的方法,那些方法也只适合在app.config或者web.config中,如果您的配置参数较多, 或者打算将一些数据以配置文件的形式单独保存,那么,直接读写整个XML将会更方便。 比如:我有一个实体类,我想将它保存在XML文件中,有可能是多条记录,也可能是一条。
这次我来反过来说,假如我们先定义了XML的结构,是下面这个样子的,那么我将怎么做呢?
<ArrayOfMyCommand xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyCommand Name="InsretCustomer" Database="MyTestDb">
<Parameters>
<Parameter Name="Name" Type="DbType.String" />
<Parameter Name="Address" Type="DbType.String" />
</Parameters>
<CommandText>insret into .....</CommandText>
</MyCommand>
</ArrayOfMyCommand>