App.config和Web.config配置文件的自定义配置节点

8/10/2015来源:ASP.NET技巧人气:2446

App.config和Web.config配置文件的自定义配置节点

前言

  昨天修改代码发现了一个问题,由于自己要在WCF服务接口中添加了一个方法,那么在相应调用的地方进行更新服务就可以了,不料意外发生了,竟然无法更新。左查右查终于发现了问题。App.config配置文件中的配置貌似出现了问题。查找节点发现是如下节点:

  <configSections>    <section name="Test1" type="Demo.Section1,Demo"/>    ..............  </configSections>

我当时也只是看到了下划波浪线,才猜测是这里的问题,于是我把configSections节点注释后,重新更新WCF服务,没想到真的可以更新了,心想这是个什么节点呢,虽然之前自己也见过这个节点,但是从来没用过,于是趁此机会就进行简单的学习一下吧,以便之后说不定什么时候就会用到。

  这里我的讲解暂时之针对.NET的Web.config文件和App.confg文件,也就是对.Net配置文件自定义节点进行学习记录。

配置文件优先级

在此简单的学习一个配置文件的优先级吧,因为自己之前对配置文件接触的也比较少,没详细的进行学习过。

首先在.net提供了一个针对当前机器的配置文件,这个文件是machine.config。所在地址如下图所示。

然后此文件夹下还存在一个Web.confg的配置文件。

asp.net网站IIS启动的时候会加载配置文件中的配置信息,然后缓存这些信息,这样就不必每次去读取配置信息。在运行过程中asp.net应用程序会监视配置文件的变化情况,一旦编辑了这些配置信息,就会重新读取这些配置信息并缓存。

1、如果在当前页面所在目录下存在web.config文件,查看是否存在所要查找的结点名称,如果存在返回结果并停止查找。2、如果当前页面所在目录下不存在web.config文件或者web.config文件中不存在该结点名,则查找它的上级目录,直到网站的根目录。

3、如果网站根目录下不存在web.config文件或者web.config文件中不存在该节点名则在C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config/web.config文件中查找。(这是我本机的地址,请根据情况进行调整)4、如果在C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config/web.config文件中不存在相应结点,则在C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config/machine.config文件中查找。5、如果仍然没有找到则返回null。

所以如果我们对某个网站或者某个文件夹有特定要求的配置,可以在相应的文件夹下创建一个web.config文件,覆盖掉上级文件夹中的web.config文件中的同名配置即可。这些配置信息的寻找只查找一次,以后便被缓存起来供后来的调用。在asp.net应用程序运行过程中,如果web.config文件发生更改就会导致相应的应用程序重新启动,这时存储在服务器内存中的用户会话信息就会丢失(如存储在内存中的session)。

  所以如果我们对某个网站或者某个文件夹有特定要求的配置,可以在相应的文件夹下创建一个web.config文件,覆盖掉上级文件夹中的web.config文件中的同名配置即可。这些配置信息的寻找只查找一次,以后便被缓存起来供后来的调用。在asp.net应用程序运行过程中,如果web.config文件发生更改就会导致相应的应用程序重新启动,这时存储在服务器内存中的用户会话信息就会丢失(如存储在内存中的Session)。一些软件(如杀毒软件)每次完成对web.config的访问时就会修改web.config的访问时间属性,也会导致asp.net应用程序的重启。

常用配置文件节点appSettings和connectionSettings说明

1、<appSettings>节点

<appSettings>节点主要用来存储asp.net应用程序的配置信息,例如网站上传文件的类型:

<appSettings>    <!--允许上传的图片格式类型-->    <add key="ImageType" value=".jpg;.bmp;.gif;.png;.jpeg"/>    <!--允许上传的文件类型-->    <add key="FileType" value=".jpg;.bmp;.gif;.png;.jpeg;.pdf;.zip;.rar;.xls;.doc"/></appSettings>

对于<appSettings>节点中的值可以按照key来进行访问,以下就是一个读取key值为“FileType”节点值的例子:

string fileType=ConfigurationManager.AppSettings["FileType "];

2、<connectionStrings>节点

<connectionStrings>节点主要用于配置数据库连接的,我们可以<connectionStrings>节点中增加任意个节点来保存数据库连接字符串,将来在代码中通过代码的方式动态获取节点的值来实例化数据库连接对象,这样一旦部署的时候数据库连接信息发生变化我们仅需要更改此处的配置即可,而不必因为数据库连接信息的变化而需要改动程序代码和重新部署。数据库链接示例如下:

  <connectionStrings>    <add name="OraPRofileConnString" connectionString="user id=admin;data source=CRMDB;passWord=123456;" providerName="System.Data.OracleClient"/>  </connectionStrings>

在代码中我们可以这么实例化数据库连接对象:

///1读取web.config文件节点配置string ConnectionStringProfile = ConfigurationManager.ConnectionStrings["OraProfileConnString"].ConnectionString;///2实例化OracleConnection对象OracleConnection conn = new OracleConnection(ConnectionStringProfile);

这样做的好处是一旦开发时所用的数据库和部署时的数据库不一致,仅仅需要用记事本之类的文本编辑工具编辑connectionString属性的值就行了。

自定义节点配置解析

经过查阅资料发现,有些人和我一样,只用过我上面说的两个节点,但是如果参数过多,这种做法的缺点也会明显地暴露出来:appSetting中的配置参数项只能按key名来访问,不能支持复杂的层次节点也不支持强类型, 而且由于全都只使用这一个集合,你会发现:完全不相干的参数也要放在一起!解决的方法便是使用自定义节点配置来解析。

我们来看一下如何在app.config或者web.config中增加一个自定义的配置节点。 在这篇博客中,我将介绍4种自定义配置节点的方式。

1、第一种情况——Property

配置文件如下,依照属性的方式处理:

<?xml version="1.0" encoding="utf-8" ?><configuration>  <configSections>    <section name="Test1" type="Demo.Section1,Demo"/>  </configSections>  <Test1 UserName="aehyok" Path="www.cnblogs.com/aehyok"></Test1></configuration>

自定义一个类,以ConfigurationSection为基类,各个属性要加上[ConfigurationProperty] ,ConfigurationProperty的构造函数中传入的name字符串将会用于config文件中,表示各参数的属性名称。

属性的值的读写要调用this[],由基类去保存。

为了能使用配置节点能被解析,需要在<configSections>中注册,代码如上<section name="Test1" type="Demo.Section1,Demo"/>。

实现代码如下:

namespace Demo{    public class Section1 : ConfigurationSection    {        [ConfigurationProperty("UserName")]        public string UserName        {            get { return this["UserName"].ToString(); }            set { this["UserName"] = value; }        }        [ConfigurationProperty("Path")]        public string Path        {            get { return this["Path"].ToString(); }            set { this["Path"] = value; }        }    }}

下面将要介绍另三种配置节点虽然复杂一点,但是一些基础的东西与这个节点是一样的,所以后面我就不再重复说明了。

2、第二种情况——Element

配置文件如下:

<?xml version="1.0" encoding="utf-8" ?><configuration>  <configSections>    <section name="Test2" type="Demo.Section2,Demo"/>  </configSections>  <Test2>    <Users UserName="aehyok" Password="123456"></Users>  </Test2></configuration>

实现代码如下:

namespace Demo{    public class Section2 : ConfigurationSection    {        [ConfigurationProperty("Users", IsRequired = true)]        public SectionElement Users        {            get { return (SectionElement)this["Users"]; }        }        public class SectionElement : ConfigurationElement        {            [ConfigurationProperty("UserName", IsRequired = true)]            public string UserName            {                get { return this["UserName"].ToString(); }                set { this["UserName"] = value; }            }            [ConfigurationProperty("Password", IsRequired = true)]            public string Password            {                get { return this["Password"].ToString(); }                set { this["Password"] = value; }            }        }    }}

第二种情况比第一种情况的区别就是,数据类型也是自己定义的,具体的配置属性写在ConfigurationElement的继承类中。

3、第三种情况——CDATA

CDATA可以包含比较长的字符串,且可以包含HTML代码段,这样针对特殊字符的存放也比较方便。假如如下配置:

<?xml version="1.0" encoding="utf-8" ?><configuration>  <configSections>    <section name="Test3" type="Demo.Section3,Demo"/>  </configSections>  <Test3>    <T1>      <![CDATA[      Create proc insert_bank @param1 char(10),@param2 varchar(20),@param3 varchar(20),@param4 int,@param5 int output        with encryption ---------加密        as        insert bankMoney (id,userID,sex,Money)        Values(@param1,@param2,@param3, @param4)        select @param5=sum(Money) from bankMoney where userID='Zhangsan'        go      ]]>    </T1>    <T2>      <![CDATA[        <html>        <head>            <title>Test</title>        </head>        <body>            This is Test。        </body>        </html>      ]]>    </T2>  </Test3></configuration>

代码实现如下:

namespace Demo{    public class Section3 : ConfigurationSection    {        [ConfigurationProperty("T1", IsRequired = true)]        public MyTextElement Command1        {            get { return (MyTextElement)this["T1"]; }        }        [ConfigurationProperty("T2", IsRequired = true)]        public MyTextElement Command2        {            get { return (MyTextElement)this["T2"]; }        }    }    public class MyTextElement : ConfigurationElement    {        protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey)        {            CommandText = reader.ReadElementContentAs(typeof(string), null) as string;        }        protected override bool SerializeElement(XmlWriter writer, bool serializeCollectionKey)        {            if (writer != null)                writer.WriteCDat