• 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

    希望有用,谢谢…

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

  • 相关阅读:
    进程虚拟内存
    非连续内存区缺页异常处理
    请求调页和写时复制
    标签对齐(补充)
    shell数学表达式
    缺页异常的处理
    不错的书籍
    imag database2
    image database
    Apache down了?
  • 原文地址:https://www.cnblogs.com/scy251147/p/2306504.html
Copyright © 2020-2023  润新知