Asp.net配置文件中自定义节点详解

在开发Asp.net站点的时候,我们会遇到很多的配置参数:网站名称,上传图片后缀,上传文件后缀,关键字过滤,数据库连接字串等等,这些内容如果比较少的话,直接配置到Web.config文件中,借由.NET提供的操作类,将会非常方便的来操作这些自定义配置节点,以下文章只是在Fish-Li的文章基础上而来,具体内容如下:

首先,配置一个最简单的节点,类似

<MySection username="程序诗人" url="http://scy251147.cnblogs.com" comment="注意啦!!!!!!" />

这个该如何来进行呢? 

在Web.Config中,如果想配置这样的自定义节点,需要首先在configuration节点下的configSections节点中进行注册,如下:

<section name="MySection" type="WebApplication1.MySection,WebApplication1"/>

这样,我们只需要将MySection节点配置在configuration节点下即可,具体的ScreenShot如下:

那么如何在界面上展示出来呢?首先得需要定义一个类继承自ConfigurationSection才可以继续后面的操作.

using System.Configuration;

namespace WebApplication1
{
public class MySection:ConfigurationSection
{
[ConfigurationProperty("username", IsRequired = true)]
public string UserName
{
get { return this["username"].ToString(); }
set { this["username"] = value; }
}

[ConfigurationProperty("url", IsRequired = true)]
public string Url
{
get { return this["url"].ToString(); }
set { this["url"] = value; }
}

[ConfigurationProperty("comment", IsRequired = true)]
public string Comment
{
get { return this["comment"].ToString(); }
set { this["comment"] = value; }
}
}
}

在界面上可以通过如下方式来显示:

 MySection mySection = (MySection)ConfigurationManager.GetSection("MySection");
Response.Write(mySection.UserName + "----" + mySection.Url+"----"+mySection.Comment);

其次对于一个稍微复杂一点的自定义节点,这个自定义节点下面有子节点,这个该如何来进行呢?类似:

 <MySectionWithChild>

<users username="程序诗人" url="http://scy251147.cnblogs.com" comment="注意啦!!!!!" />

</MySectionWithChild>

这个在Web.Config中的配置和前面类似,就是先注册节点,然后将节点放到configuration节点下:

当然,如果要访问这个自定义节点,也需要通过类来配置,我们得首先定义一个父节点类,父节点类包含子节点元素:

父节点类:

using System.Configuration;

namespace WebApplication1
{
public class MySectionParent:ConfigurationSection
{
[ConfigurationProperty("users", IsRequired = true)]
public MySectionWithChild Users
{
get { return (MySectionWithChild)this["users"]; }
}
}
}

子节点类(注意这里的子节点类需要继承自ConfigurationElement类):

using System.Configuration;

namespace WebApplication1
{
public class MySectionWithChild:ConfigurationElement
{
[ConfigurationProperty("username", IsRequired = true)]
public string UserName
{
get { return this["username"].ToString(); }
set { this["username"] = value; }
}

[ConfigurationProperty("url", IsRequired = true)]
public string Url
{
get { return this["url"].ToString(); }
set { this["url"] = value; }
}

[ConfigurationProperty("comment", IsRequired = true)]
public string Comment
{
get { return this["comment"].ToString(); }
set { this["comment"] = value; }
}
}
}

如何在界面上使用呢?可以通过如下的方式:

  MySectionParent mySectionParent = (MySectionParent)ConfigurationManager.GetSection("MySectionWithChild");
MySectionWithChild users = mySectionParent.Users;
Response.Write(users.UserName + "----" + users.Url + "----" + users.Comment);

再者,我们知道xml文件中是不能包含形如<的关键字符的,这将导致xml报错.假设我们将SQL语句配置在了配置文件中,那么这种关键字是不可避免的,当然,遇到这种问题我们可以利用CDATA标签来避免,假设在配置文件中存在CDATA标签,我们该如何读取其数据呢?先看节点配置:

这种情况和第二种类似,即一个父节点,里面包含有子节点,当然也需要两个类支持,一个类继承自ConfigurationSection,而另一个类继承自ConfigurationElement,类操作代码如下:

父节点类:

using System.Configuration;

namespace WebApplication1
{
public class MySectionWithPlainTextCollection:ConfigurationSection
{
[ConfigurationProperty("CommandOne", IsRequired = true)]
public MySectionWithPlainText CommandOne
{
get { return (MySectionWithPlainText)this["CommandOne"]; }
}

[ConfigurationProperty("CommandTwo", IsRequired = true)]
public MySectionWithPlainText CommandTwo
{
get { return (MySectionWithPlainText)this["CommandTwo"]; }
}
}
}

子节点类:

using System.Configuration;

namespace WebApplication1
{
public class MySectionWithPlainText:ConfigurationElement
{

[ConfigurationProperty("data", IsRequired = true)]
public string CommandText
{
get { return this["data"].ToString(); }
set { this["data"] = value; }
}

//反序列化
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;
}
}
}

需要说明一下,在进行这样的自定义节点操作的时候,系统已经通过重载序列化和反序列化标志,对特殊字符进行了还原处理.在界面上显示的做法如下:

MySectionWithPlainTextCollection planCommand = (MySectionWithPlainTextCollection)ConfigurationManager.GetSection("MySectionWithPlainText");

//这条命令里面我专门放置了小于号(<)用来测试其正确性
Response.Write(planCommand.CommandOne.CommandText.ToString()+"</br>");
Response.Write(planCommand.CommandTwo.CommandText.ToString()+"</br>");

最后,是我们最熟悉的,即在通过ConnectionString配置数据库连接字串的时候经常遇到的含有key值和value值的节点:

像这种自定义节点,使用的是比较多的,大多属于配置型的,我们该如何来进行读取呢?像这种具有键值对的,读取方法和上面类似,只是稍微麻烦了一点,我们当然还是首先定义一个父节点类,同样继承自ConfigurationSection:

using System.Configuration;

namespace WebApplication1
{
public class MySectionCollection:ConfigurationSection
{
private static readonly ConfigurationProperty property = new ConfigurationProperty(string.Empty, typeof(MySectionKeyValue), null, ConfigurationPropertyOptions.IsDefaultCollection);

[ConfigurationProperty("",Options = ConfigurationPropertyOptions.IsDefaultCollection)]
public MySectionKeyValue KeyValues
{
get { return (MySectionKeyValue)base[property]; }
}
}
}

由于这样的自定义节点含有多个<add …></add>标签,所以我们得需要定义一个ConfigurationElementCollection的集合,这个集合中可以通过索引方式来获取单个的键值对,方法中包含了对Element的创建,删除,获取的功能:

using System.Configuration;
using System;

namespace WebApplication1
{
[ConfigurationCollection(typeof(MySectionKeyValueSettings))]
public class MySectionKeyValue : ConfigurationElementCollection
{
public MySectionKeyValue()
: base(StringComparer.OrdinalIgnoreCase) //忽略大小写
{

}

//其实关键就是这个索引器,但它也是调用基类的实现,只是做下类型转换就行了
new public MySectionKeyValueSettings this[string name]
{
get
{
return (MySectionKeyValueSettings)base.BaseGet(name);
}
}

//下面二个方法中抽象类中必须要实现的
protected override ConfigurationElement CreateNewElement()
{
return new MySectionKeyValueSettings();
}

protected override object GetElementKey(ConfigurationElement element)
{
return ((MySectionKeyValueSettings)element).Key;
}

//说明:如果不需要在代码中修改集合,可以不实现Add,Clear,Remove
public void Add(MySectionKeyValueSettings setting)
{
this.BaseAdd(setting);
}

public void Clear()
{
this.BaseClear();
}

public void Get(MySectionKeyValueSettings setting)
{
this.BaseGet(setting.Key);
}

public void Remove(string name)
{
base.BaseRemove(name);
}
}
}

最后是单个键值对类,继承自ConfigurationElement:

using System.Configuration;

namespace WebApplication1
{
public class MySectionKeyValueSettings: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; }
}
}
}

使用方式如下:

 MySectionCollection sectionCollection = (MySectionCollection)ConfigurationManager.GetSection("MySectionCollection");
sResponse.Write(string.Join("</br>",(
from kv in sectionCollection.KeyValues.Cast<MySectionKeyValueSettings>()
let s=string.Format("{0}={1}",kv.Key,kv.Value)
select s).ToArray()
));

这样,通过上面的四个步骤,我们就可以读取自定义节点的值,显示效果如下:

 至于修改节点内容的方法,我就不过于多说了,比较简单,见如下代码:

#region 编辑节点

Configuration config = WebConfigurationManager.OpenWebConfiguration("/");

protected void Button1_Click(object sender, EventArgs e)
{
MySection section1 = config.GetSection("MySection") as MySection;
section1.Comment = "注意啦,我是修改以后的内容!!!!!!";
ConfigurationManager.RefreshSection("MySection");
config.Save();

Response.Write(section1.UserName + "----" + section1.Url + "----" + section1.Comment);
}

protected void Button2_Click(object sender, EventArgs e)
{
MySectionParent section2 = config.GetSection("MySectionWithChild") as MySectionParent;
section2.Users.Comment = "注意啦,我也是修改以后的内容!!!!!";
ConfigurationManager.RefreshSection("MySectionWithChild");
config.Save();

Response.Write(section2.Users.UserName + "----" + section2.Users.Url + "----" + section2.Users.Comment);
}

protected void Button3_Click(object sender, EventArgs e)
{
MySectionWithPlainTextCollection section3 = config.GetSection("MySectionWithPlainText") as MySectionWithPlainTextCollection;
section3.CommandOne.CommandText = "select * from trade";
ConfigurationManager.RefreshSection("MySectionWithPlainText");
config.Save();

Response.Write(section3.CommandOne.CommandText.ToString() + "</br>");
Response.Write(section3.CommandTwo.CommandText.ToString() + "</br>");
}

protected void Button4_Click(object sender, EventArgs e)
{
MySectionCollection section4 = config.GetSection("MySectionCollection") as MySectionCollection;
MySectionKeyValueSettings setting = new MySectionKeyValueSettings();
setting.Key = "testnode";
setting.Value = "testvalue";
section4.KeyValues.Add(setting);

config.Save();

Response.Write(string.Join("</br>", (
from kv in section4.KeyValues.Cast<MySectionKeyValueSettings>()
let s = string.Format("{0}={1}", kv.Key, kv.Value)
select s).ToArray()
));
}
#endregion

希望有用,谢谢…

源代码下载:点击这里下载

原文地址:https://www.cnblogs.com/scy251147/p/2306504.html