自定义配置节处理类
今天看别人的代码,发现原来是可以 自定义配置文件处理类 的。
在此之前,先弄清两个概念:配置节和配置元素
什么是配置节和配置元素?
下面给出一段XML:
<system.webServer> <handlers> <add name="CrystalImageHandler.aspx_GET" verb="GET" path="CrystalImageHandler.aspx" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=12.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" preCondition="integratedMode" /> </handlers> <httpProtocol> <customHeaders> <add name="X-UA-Compatible" value="IE=EmulateIE7" /> </customHeaders> </httpProtocol> <directoryBrowse enabled="true" /> </system.webServer>
其中的<system.webServer></system.webServer>这样的成对出现、且可包含其他配置节或配置元素的,称之为配置节。
而配置元素:如其中的<directoryBrowse />这样以"/"结尾的配置项,称为配置元素。
而不管配置节或是配置元素都可以有属性,如:<directoryBrowse />中的enabled,属性是一个名值对。如:enabled="true"。
如何定义自定义配置节和配置元素
比如,我现在想定义如下的配置项:
<xhm.erp.remoting> <server host="127.0.0.1" port="8023" /> </xhm.erp.remoting>
如果只是在配置文件中定义了上面的配置节,是不起任何作用的,因为无法去读取其中的元素及其属性值。所以,需要自定义配置节处理类 。
下面就以上面提到的配置节的定义为例,进行讲解如何自定义配置节处理程序,使得可以从配置文件中正确解析如上配置节中的信息。
自定义配置节类(代码):
/// <summary> /// 自定义配置节 /// </summary> public class CustomSection:ConfigurationSection { private const string SECTION_NAME = "xhm.erp.remoting";//节名 private const string ELEMENT_NAME = "server";//元素名 /// <summary> /// 获得自定义配置节 /// </summary> /// <returns></returns> internal static CustomSection getCustomSection() { return ConfigurationManager.GetSection(SECTION_NAME) as CustomSection; } /// <summary> /// Server元素 --- 未设为public,为什么?为了只让本程序集中的代码进行访问 /// </summary> [ConfigurationProperty("server",IsRequired=true)] internal CustomElement ServerElement { get { return base[ELEMENT_NAME] as CustomElement; } set { base[ELEMENT_NAME] = value; } } } /// <summary> /// 自定义元素(包含两个属性: host和port) /// </summary> public class CustomElement : ConfigurationElement { private const string HOST = "host";//主机名 private const string PORT = "port";//端口 /// <summary> /// 主机 /// </summary> [ConfigurationProperty("host",DefaultValue="127.0.0.1",IsRequired=true)] public string Host { get { return (string)base[HOST]; } set { base[HOST] = value; } } /// <summary> /// 端口 /// </summary> [ConfigurationProperty("port", DefaultValue = 12000)] [IntegerValidator(MinValue = 10000, MaxValue = 30000)] public int Port { get { return (int)base[PORT]; } set { base[PORT] = value; } } }
上面就是针对xhm.erp.remoting节的结构定义的自定义配置文件节,有了它才可以通过ConfigurationManager.GetSection("xhm.erp.remoting")的方式获得该自定义配置节。因为GetSection方法返回的是一个object对象,需要还需要将其强转为CustomSection类型。
其实,如果在别的项目中引用该自定义配置节还是有一些问题的,因为ServerElement的访问修饰符定义为internal,这就意味着只有在本程序集中的代码才能访问该属性。
之所以在这里这样定义,是因为以后会在CustomSection类所在程序集中定义具体的ServerConfiguration和ClientCongfiguration类,以用于访问服务端和客户端的自定义配置节。这样就不需要直接获得ServerElement属性了。
定义了自定义配置节后,如何去用?
方法比较简单,直接在需要读配置文件的地方使用如下代码:
CustomSection cs = (CustomSection)ConfigurationManager.GetSection("xhm.erp.remoting");
但是在程序运行的过程中还是出现了一些问题:
1)首先,读取配置文件时,提示异常:配置系统未能初始化
InnerException: "无法识别的配置节 xhm.erp.remoting"
原因:
未在配置文件中声明自定义配置节。
解决:
在配置文件的configuration节的开头加入如下内容:
<configSections> <section name="xhm.erp.remoting" type="Com.Xhm.RemotingConfiguration.CustomSection,RemotingConfiguration, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowDefinition="Everywhere" allowExeDefinition="MachineToApplication" restartOnExternalChanges="true" /> </configSections>
对自定义配置节进行声明,否则会报错。
一个用户自定义的配置节,在配置文件中分为两部分:
一是在<configSections></ configSections>配置节中声明配置节(上面配置文件模式中的“<section>”),
另外是在<configSections></ configSections >之后设置配置节(上面配置文件模式中的“<xhm.erp.remoting>”),有点类似一个变量先声明,后使用一样。
所以完整的配置文件内容如下:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="xhm.erp.remoting" type="Com.Xhm.RemotingConfiguration.CustomSection,RemotingConfiguration, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowDefinition="Everywhere" allowExeDefinition="MachineToApplication" restartOnExternalChanges="true" /> </configSections> <xhm.erp.remoting> <!--<server host="192.168.3.1" port="16890" />--> <!---不配置port,则默认端口为12000--> <server host="127.0.0.1" /> </xhm.erp.remoting> </configuration>
2)其次,又报了如下错误:提供的验证程序不支持属性“port”的类型。
原因:
/// <summary> /// 端口 /// </summary> [ConfigurationProperty("port",IsRequired=true),IntegerValidator(MinValue=10000,MaxValue=30000)] public string Port { get { return (string)base[PORT]; } set { base[PORT]=value; } }
属性定义代码中有不一致的地方,如这里的port定义为string类,但是在进行数据验证时,却是用整型的验证方法IntegerValidator。
解决:
把port的类型该为int。
3)然后,又发现用ConfigurationManager.GetSection("xhm.erp.remoting");读取自定义配置节时,又提示:
{"属性“port”的值无效。错误为: 该值必须在 10000-30000 范围内。"}
原因:
IntegerValidator(MinValue=10000,MaxValue=30000)对数字进行限定时,好像必须在ConfigurationProperty中指定默认值。
解决:
把CustomElement 中自定义属性的代码修改为:
/// <summary> /// 端口 /// </summary> //[ConfigurationProperty("port")] [ConfigurationProperty("port", DefaultValue = 12000)] [IntegerValidator(MinValue = 10000, MaxValue = 30000)] public int Port { get { return (int)base[PORT]; } set { base[PORT] = value; } }
如果读取的server的host和port都是默认值,而不是在配置文件中配置的值。为什么?
浙公网安备 33010602011771号