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:WindowsMicrosoft.NETFrameworkv4.0.30319Config/web.config文件中查找。(这是我本机的地址,请根据情况进行调整)
4、如果在C:WindowsMicrosoft.NETFrameworkv4.0.30319Config/web.config文件中不存在相应结点,则在C:WindowsMicrosoft.NETFrameworkv4.0.30319Config/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 _bank @param1 char(10),@param2 varchar(20),@param3 varchar(20),@param4 int,@param5 int output
with encryption ---------加密
as
bankMoney (id,userID,sex,Money)
Values(@param1,@param2,@param3, @param4)
@param5=sum(Money) 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.WriteCData(CommandText);
return true;
}

[ConfigurationProperty("data", IsRequired = false)]
public string CommandText
{
get { return this["data"].ToString(); }
set { this["data"] = value; }
}
}
}

这里由我们控制对数据的读写操作,也就是要重载方法SerializeElement,DeserializeElement。

4、第四种情况——Collection

配置信息如下:


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="Test4" type="Demo.Section4,Demo"/>
</configSections>
<Test4>
<add key="1" value="aehyok"></add>
<add key="2" value="Leo"></add>
<add key="3" value="Lynn"></add>
</Test4>
</configuration>

为每个集合中的参数项创建一个从ConfigurationElement继承的派生类,可参考Section1。

为集合创建一个从ConfigurationElementCollection继承的集合类,具体在实现时主要就是调用基类的方法。

在创建ConfigurationSection的继承类时,创建一个表示集合的属性就可以了,注意[ConfigurationProperty]的各参数。

实现代码如下:


namespace Demo
{
public class Section4 : ConfigurationSection
{
private static readonly ConfigurationProperty s_property
= new ConfigurationProperty(string.Empty, typeof(MyKeyValueCollection), null,
ConfigurationPropertyOptions.IsDefaultCollection);

[ConfigurationProperty("", Options = ConfigurationPropertyOptions.IsDefaultCollection)]
public MyKeyValueCollection KeyValues
{
get
{
return (MyKeyValueCollection)base[s_property];
}
}
}

[ConfigurationCollection(typeof(MyKeyValueSetting))]
public class MyKeyValueCollection : ConfigurationElementCollection // 自定义一个集合
{
// 基本上,所有的方法都只要简单地调用基类的实现就可以了。

public MyKeyValueCollection()
: base(StringComparer.OrdinalIgnoreCase) // 忽略大小写
{
}

// 其实关键就是这个索引器。但它也是调用基类的实现,只是做下类型转就行了。
new public MyKeyValueSetting this[string name]
{
get
{
return (MyKeyValueSetting)base.BaseGet(name);
}
}

// 下面二个方法中抽象类中必须要实现的。
protected override ConfigurationElement CreateNewElement()
{
return new MyKeyValueSetting();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((MyKeyValueSetting)element).Key;
}

// 说明:如果不需要在代码中修改集合,可以不实现Add, Clear, Remove
public void Add(MyKeyValueSetting setting)
{
this.BaseAdd(setting);
}
public void Clear()
{
base.BaseClear();
}
public void Remove(string name)
{
base.BaseRemove(name);
}
}

public class MyKeyValueSetting : 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; }
}
}

读取配置文件信息

四个Read进行读取数据的代码如下:


        private void button1_Click(object sender, EventArgs e)
{
Section1 sectioin1 = (Section1)ConfigurationManager.GetSection("Test1");
txtUserName.Text = sectioin1.UserName;
txtPath.Text = sectioin1.Path;
}

private void button4_Click(object sender, EventArgs e)
{
Section2 sectioin2 = (Section2)ConfigurationManager.GetSection("Test2");
txtUName.Text = sectioin2.Users.UserName;
txtPassword.Text = sectioin2.Users.Password;
}

private void button6_Click(object sender, EventArgs e)
{
Section3 section3 = (Section3)ConfigurationManager.GetSection("Test3");
T1.Text = section3.T1.CommandText.Trim();
T2.Text = section3.T2.CommandText.Trim();
}

private void button8_Click(object sender, EventArgs e)
{
Section4 section4 = (Section4)ConfigurationManager.GetSection("Test4");
txtKeyValues.Text = string.Join("",
( kv in section4.KeyValues.Cast<MyKeyValueSetting>()
let s = string.Format("{0}={1}", kv.Key, kv.Value)

s).ToArray());
}

执行点击之后数据读取如下图所示,也就是数据读取成功。

在读取自定节点时,我们需要调用ConfigurationManager.GetSection()得到配置节点,并转换成我们定义的配置节点类,然后就可以按照强类型的方式来访问了。

写入配置文件信息

首先定义一个全局变量,代码如下


 Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

四个Write保存按钮如下:


        private void button2_Click(object sender, EventArgs e)
{
Section1 sectioin1 = config.GetSection("Test1") as Section1;
sectioin1.UserName = txtUserName.Text;
sectioin1.Path = txtPath.Text;
config.Save();
}
private void button3_Click(object sender, EventArgs e)
{
Section2 sectioin2 = config.GetSection("Test2") as Section2;
sectioin2.Users.UserName = txtUName.Text;
sectioin2.Users.Password = txtPassword.Text;
config.Save();
}

private void button5_Click(object sender, EventArgs e)
{
Section3 section3 = config.GetSection("Test3") as Section3;
section3.T1.CommandText = T1.Text.Trim();
section3.T2.CommandText = T2.Text.Trim();
config.Save();
}
private void button7_Click(object sender, EventArgs e)
{
Section4 section4 = config.GetSection("Test4") as Section4;
section4.KeyValues.Clear();

( s in txtKeyValues.Lines
let p = s.IndexOf(""="")
where p > 0
new MyKeyValueSetting { Key = s.Substring(0, p), Value = s.Substring(p + 1) }
).ToList()
.ForEach(kv => section4.KeyValues.Add(kv));

config.Save();
}

在修改配置节点前,我们需要调用ConfigurationManager.OpenExeConfiguration(),然后调用config.GetSection()在得到节点后,转成我们定义的节点类型,
然后就可以按照强类型的方式来修改我们定义的各参数项,最后调用config.Save();即可。 .net为了优化配置节点的读取操作,会将数据缓存起来,如果希望使用修改后的结果生效,您还需要调用ConfigurationManager.RefreshSection方法。如果是修改web.config,则需要使用
WebConfigurationManager。

最终修改效果展示动态图

总结

1、本文主要参考大神作品http://www.cnblogs.com/fish-li/archive/2011/12/18/2292037.html从中学习取经。

2、通过本文本人也学习到了很多关于配置文件的知识,之前都没有接触学习过。

3、打算再将其他的节点设置进行学习记录下。

4、本文示例代码链接http://pan.baidu.com/s/1o6JgUBg

5、ConfigSource的使用也比较有意思,自己之前整理的一篇文章,可惜在真实项目中没用过。

例如:


 <appSettings configSource="configMy.config" />

就是关于appSettings下的配置节点都配置到了configMy.config文件中。

有关博文链接http://www.cnblogs.com/aehyok/archive/2013/05/23/3095019.html

App.config和Web.config配置文件的自定义配置节点,布布扣,bubuko.com

时间: 2024-10-20 00:09:12

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

两种读写配置文件的方案(app.config与web.config通用)

第一种方法:采用MS现有的ConfigurationManager来进行读写 using System.Configuration; namespace Zwj.TEMS.Common { public abstract class ConfigHelper { private ConfigHelper() { } /// <summary> /// 获取配置值 /// </summary> /// <param name="key"></pa

创建自定义配置节点(web.config和app.config都适用)

无论是web程序.windows程序.windows service程序,配置文件都是少不了的.我们都习惯了将连接字符串放在ConnectionString节点中,将程序的设置放在appSetting节点中.配置文件的管理程序为我们提供了方便的管理方式,那么,我们如何自定义配置节点呢? 有两种方法,其一,继承IConfigurationSectionHandler,通过实现Create方法.这种方法的灵活度非常大,我们需要动手解析自定义节点的XmlNode,所以,实现起来也比较复杂.其二,继承C

Visual Studio中xml文件使用app.config、web.config等的智能提示的方法

在.Net开发的过程中,有时我们需要使用Xml文件作为配置文件(基于某些情况的考虑),而不是app.config.web.config这种,但是我们在xml中配置时希望可以增加类似编辑app.confg.web.config文件时的智能提示. 没有作特殊配置时,编写xml文件如下: 从上图可以看到,没有智能提示.但是我们编辑app.config.web.config时有智能提示,比如上面的configuration,我们可能只要输入前面几个字母就会弹出智能提示,然后可以直接从下来中选择.如下图:

ASP.NET一个网站内存放多个config文件(Web.Config文件中configSource

每个网站里都会有一个web.config文件.修改Web.config文件会导致IIS重启,就是随意的回车一下也会导致重启.微软建议,不要将需要修改的配置内容保存在web.config中.而是单独放在一个config中.但是对于单独存放的config文件,怎么来对其进行修改和读取呢? 例如 可以指定 web.config 中的 appSetting 单独放在 一个 config.config 文件中.通过 configSource 来指定. 一.原来的web.config文件: <?xml ve

.Net 配置文件——继承ConfigurationSection实现自定义处理类处理自定义配置节点

除了使用继承IConfigurationSectionHandler的方法定义处理自定义节点的类,还可以通过继承ConfigurationSection类实现同样效果. 首先说下.Net配置文件中一个潜规则: 在配置节点时,对于想要进行存储的参数数据,可以采用两种方式:一种是存储到节点的属性中,另一种是存储在节点的文本中. 因为一个节点可以有很多属性,但是只要一个innertext,而要在程序中将这两种形式区分开会带来复杂性. 为了避免这个问题,.net的配置文件只是用属性存储而不使用inner

.Net 配置文件--继承ConfigurationSection实现自定义处理类处理自定义配置节点

除了使用继承IConfigurationSectionHandler的方法定义处理自定义节点的类,还可以通过继承ConfigurationSection类实现同样效果. 首先说下.Net配置文件中一个潜规则: 在配置节点时,对于想要进行存储的参数数据,可以采用两种方式:一种是存储到节点的属性中,另一种是存储在节点的文本中. 因为一个节点可以有很多属性,但是只要一个innertext,而要在程序中将这两种形式区分开会带来复杂性. 为了避免这个问题,.net的配置文件只是用属性存储而不使用inner

C# 快捷使用自定义配置节点

C#除了appSettings和connectionStrings默认配置外还允许用户自定义使用配置.C# 提供3中简单的自定义配置,配置文件如下 <?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="Config1" type="System.Configuration.S

加密配置文件(App.Config和Web.config)中connectionStrings通用方法

1. 背景:根据项目的要求,需要对配置文件配置的数据库连接字符串进行加密,也就是对ConnectinString节点的内容进行加密存储,同时考虑到代码使用连接字符串不需要进行更改,C#会自动对加密的内容进行解密. 2.需求:因此考虑单独开发一个winform程序,对配置文件进行加密和解密,通过ConfigurationManager中的OpenMappedExeConfiguration方法创建一个Configuration对象,然后在对这个对象中的指定节点进行操作. 遇到的问题: Config

ASP.NET配置文件Web.config 详细解释

一.认识Web.config文件 Web.config文件是一个XML文本文件,它用来储存 ASP.NET Web 应用程序的配置信息(如最常用的设置ASP.NET Web 应用程序的身份验证方式),它可以出现在应用程序的每一个目录中.当你通过VB.NET新建一个Web应用程序后,默认情况下会在根目录自动创建一个默认的   Web.config文件,包括默认的配置设置,所有的子目录都继承它的配置设置.如果你想修改子目录的配置设置,你可以在该子目录下新建一个Web.config文件.它可以提供除从