自定义配置节的常见问题

在开发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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值