无论是web程序、windows程序、windows service程序,配置文件都是少不了的。我们都习惯了将连接字符串放在ConnectionString节点中,将程序的设置放在appSetting节点中。配置文件的管理程序为我们提供了方便的管理方式,那么,我们如何自定义配置节点呢?
有两种方法,其一,继承IConfigurationSectionHandler,通过实现Create方法。这种方法的灵活度非常大,我们需要动手解析自定义节点的XmlNode,所以,实现起来也比较复杂。其二,继承ConfigurationSection,这种方法就简单多了,只需要指定对应的属性名称即可。
本文旨在使用最少的代码实现自定义配置节点,所以果断放弃第一种方法,使用第二种方法实现自定义配置节点。
光说不练假把式,接下来我们就着手使用第二种方法实现自定义配置节点。步骤如下:
1.在configSections节点中定义自定义配置节点信息
<configSections>
<section name="custom" type="SampleWebConfigSection.Configuration.customSection, SampleWebConfigSection" />
</configSections>
- name:自定义配置节点的名称
- type:类型,自定义配置节点对应的数据类型
<custom fileName="Default.txt" maxUsers="2500" maxIdleTime="00:10:00" />
3.编程实现节点的访问
using System.Configuration;
using System;
namespace SampleWebConfigSection.Configuration
{
public class customSection : ConfigurationSection
{
[ConfigurationProperty("fileName", DefaultValue = "default.txt", IsRequired = true, IsKey = false)]
[StringValidator(InvalidCharacters = " ~!@#$%^&*()[]{}/;'\"|\\", MinLength = 1, MaxLength = 60)]
public string FileName
{
get { return (string)this["fileName"]; }
set { this["fileName"] = value; }
}
[ConfigurationProperty("maxUsers", DefaultValue = (long)10000, IsRequired = false)]
[LongValidator(MinValue = 1, MaxValue = 10000000, ExcludeRange = false)]
public long MaxUsers
{
get { return (long)this["maxUsers"]; }
set { this["maxUsers"] = value; }
}
[ConfigurationProperty("maxIdleTime", DefaultValue = "0:10:0", IsRequired = false)]
[TimeSpanValidator(MinValueString = "0:0:30", MaxValueString = "5:00:0", ExcludeRange = false)]
public TimeSpan MaxIdleTime
{
get { return (TimeSpan)this["maxIdleTime"]; }
set { this["maxIdleTime"] = value; }
}
}
}
- ConfigurationProperty标记:指示 .NET Framework 通过custom节点的属性来实例化对象的字段值。对于每一个标记有此特性的属性,.NET Framework 都使用反射来读取修饰参数,并创建相关的 ConfigurationProperty 实例。
- StringValidator标记:以声明的方式指示 .NET Framework 对配置属性执行字符串验证。
- LongValidator标记:以声明的方式指示 .NET Framework 对配置属性执行长整型验证。
- TimeSpanValidator标记:以声明的方式指示 .NET Framework 对配置属性执行时间验证。
customSection custom = (customSection)System.Configuration.ConfigurationManager.GetSection("custom");
Response.Write(custom.FileName + "|" + custom.MaxUsers.ToString() + "|" + custom.MaxIdleTime);
在第一句代码中,我们通过ConfigurationManager.GetSection获取custom节点,并强制类型转换为我们自定义的节点,这样就能够方便的使用了。
OK,第一个例子完成。其实这个例子是MSDN中的,我将它拿下来,稍加说明而已。
当然,只有上面这些内容是不足以放首页的。上面的例子并不能完全满足我们常规的需求,甚至我们可以把这些配置放在appSetting中来替代我们的自定义配置节点。下面介绍一个实际的需求:
在网站的建设中,我们希望将网站的标题、副标题和网址放在一条配置中,因为网站有文件上传功能,我们希望在配置中限制上传文件的大小,并针对不同的上传类型将文件放在不同的目录中。定以后的节点结构如下:
<webSetting>
<base title="草屋&拾荒" subTitle="七千米深蓝的博客" url="http://youring2.cnblogs.com"></base>
<fileUpload>
<file name="headPhoto" path="upload/image/headPhoto" size="200"></file>
<file name="album" path="upload/image/album" size="1024"></file>
</fileUpload>
</webSetting>
要完成这个自定义配置节点,按照第一个例子的步骤,我们需要现在configSections中配置自定义节点信息:
<section name="webSetting" type="SampleWebConfigSection.Configuration.webSettingSection, SampleWebConfigSection" />
不解释,接下来我们需要完成四个类:
- webSettingSection
- baseSection
- fileUploadSection
- fileSection
using System.Configuration;
namespace SampleWebConfigSection.Configuration
{
public class webSettingSection : ConfigurationSection
{
//base节点
[ConfigurationProperty("base")]
public baseSection BaseSetting { get {return (baseSection)base["base"]; } }
//fileUpload节点
[ConfigurationProperty("fileUpload")]
public fileUploadSection FileUploadSetting { get { return (fileUploadSection)base["fileUpload"]; } }
}
}
派生自ConfigurationSection,包含两个属性:BaseSetting和FileUploadSetting,这两个属性分别对应配置文件中的两个子节点base 和fileUpload。
using System.Configuration;
namespace SampleWebConfigSection.Configuration
{
public class baseSection : ConfigurationElement
{
//title属性
[ConfigurationProperty("title", IsKey = true, IsRequired = true)]
public string title { get { return (string)base["title"]; } set { title = value; } }
//subTitle属性
[ConfigurationProperty("subTitle", IsRequired = false, DefaultValue="")]
public string subTitle { get { return (string)base["subTitle"]; } set { subTitle = value; } }
//url属性
[ConfigurationProperty("url", IsRequired = true)]
public string url { get { return (string)base["url"]; } set { url = value; } }
}
}
派生自ConfigurationElement,因为它是一个子元素,被包含在webSettingSection类中。它的几个属性不作解释。
using System.Configuration;
namespace SampleWebConfigSection.Configuration
{
[ConfigurationCollection(typeof(fileSection), AddItemName = "file")]
public class fileUploadSection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new fileSection();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((fileSection)element).name;
}
public fileSection this[int index]
{
get { return (fileSection)base.BaseGet(index); }
}
new public fileSection this[string name]
{
get { return (fileSection)base.BaseGet(name); }
}
}
}
派生自ConfigurationElementCollection,因为它是一个子元素的集合,它包含一个fileSection的集合。
这个类使用了如下的标记:
[ConfigurationCollection(typeof(fileSection), AddItemName = "file")]
这是一个子元素集合的说明,第一个type参数是必须的,它指定了包含子集的类型。第二个参数是可选的,它指定了要添加到集合中的子节点的节点名,默认是是add,我们没有使用默认值,而是使用了“file”,所以在这里进行了指定。
另外,这个类还实现了通过index和name获取一个fileSection的方法,分别是this[int index]和this[string name]。基类本身存在通过字符串获取子元素的方法,所以这里要使用new关键字。
using System.Configuration;
namespace SampleWebConfigSection.Configuration
{
public class fileSection : ConfigurationElement
{
//name属性
[ConfigurationProperty("name", IsKey = true, IsRequired = true)]
public string name { get { return (string)this["name"]; } set { name = value; } }
//path属性
[ConfigurationProperty("path", IsRequired = true)]
public string path { get { return (string)this["path"]; } set { path = value; } }
//size属性
[ConfigurationProperty("size", IsRequired = true, DefaultValue = 1024)]
public int size { get { return (int)this["size"]; } set { size = value; } }
}
}
派生自ConfigurationElement。它的属性很简单,不解释。
我们可以使用如同第一个示例中使用自定义配置节点的方法使用这个配置节点。但通常我们不希望每次使用的时候都重新加载一次配置项,所以,我们通过一个静态对象来访问这个配置节点:
namespace SampleWebConfigSection.Configuration
{
public class WebSettingManager
{
public static webSettingSection WebSetting = (webSettingSection)System.Configuration.ConfigurationManager.GetSection("webSetting");
}
}
测试一下我们的自定义配置节点是否好使,在网站的页面中加入如下代码:
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<h2>
<asp:Label ID="lblTitle" Text="" runat="server" />
</h2>
<h3>
<asp:Label ID="lblSubTitle" Text="" runat="server" />
</h3>
地址:<asp:Label ID="lblUrl" Text="" runat="server" />
<p></p><p></p>
<asp:GridView ID="gvFileUploadSetting" runat="server" Width="300" BackColor="#F0F8FF" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="名称">
<HeaderStyle Width="80px" Font-Bold="true" />
<ItemStyle Font-Bold="false" />
<ItemTemplate>
<%#Eval("name")%>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="路径">
<HeaderStyle Width="160px" Font-Bold="true" />
<ItemStyle Font-Bold="false" />
<ItemTemplate>
<%#Eval("path")%>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="大小">
<HeaderStyle Width="60px" Font-Bold="true" />
<ItemStyle Font-Bold="false" />
<ItemTemplate>
<%#Eval("size")%>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</asp:Content>
protected void Page_Load(object sender, EventArgs e)
{
this.Title = WebSettingManager.WebSetting.BaseSetting.title + " - " + WebSettingManager.WebSetting.BaseSetting.subTitle;
this.lblTitle.Text = WebSettingManager.WebSetting.BaseSetting.title;
this.lblSubTitle.Text = WebSettingManager.WebSetting.BaseSetting.subTitle;
this.lblUrl.Text = WebSettingManager.WebSetting.BaseSetting.url;
this.gvFileUploadSetting.DataSource = WebSettingManager.WebSetting.FileUploadSetting;
this.gvFileUploadSetting.DataBind();
}