




已阅读5页,还剩40页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
引言几乎所有的应用程序都离不开配置,有时候我们会将配置信息存在数据库中(例如大家可能常会见到名为Config这样的表);更多时候,我们会将配置写在Web.config或者App.Config中。通过将参数写在配置文件(表)中,我们的程序将变得更加灵活,只要对参数进行修改,再由程序中的某段代码去读取相应的值就可以了。而如果直接将配置值写在程序中,当配置需要改变时,则只能通过修改代码来完成,此时往往需要重新编译程序集。本文不是讲述.Net Framework中诸多的内置结点如何设置,比如httpHandler、httpModule、membership、roleManager 等。而是讲述.Net中配置的实现方式,以及如何定义、使用我们自定义的结点。.Net 中的程序配置介绍我们首先了解下.Net 中的配置文件是如何工作的。我们看下这段代码:/ Web.Config / Default.aspx.cs protected void Page_Load(object sender, EventArgs e) Literal siteName = new Literal(); siteName.Text = ConfigurationManager.AppSettingsSiteName; form1.Controls.Add(siteName);上面这段代码大家应该再熟悉不过了,我们在appSettings结点中添加了一个add子结点,给key和value属性赋了值,然后在程序中读取了值。但是为什么可以这么做?如果我们想自定义一个配置系统,我们该怎么做呢?我们先抛开.Net的机制不谈,来看看如果自己实现一个应用程序的配置方法该如何做,我想可以是这样的:1. 首先建立一个XML文件,在这个文件中创建我们需要的结点(或者结点树),在结点的属性或者文本(innerText)中存储配置值。 2. 创建一个类,这个类的字段和属性映射XML中的某个结点下的属性和文本,以提供强类型的访问。 3. 创建一个配置文件Xml的访问类,在下面添加一个方法,比如叫GetSection(string nodeName),参数nodeName是结点(或者结点树的根节点)的名称。在方法内部,先创建第二步的类型实例,然后使用System.Xml命名空间下的方法对结点进行处理,对实例的属性进行赋值,最后返回这个实例。 4. 在程序中通过这个实例来访问配置的结点值。上面的思路应该是很清晰的,可是存在一个问题:我们的XML文件中可能会包含多个结点,而每个结点的结构可能都不相同。比如说:每个结点下的子结点可能不相同,每个结点的属性可能不相同。这样的话,我们的GetSection()方法实际上只能是针对某个特定的结点进行。那么该怎么办呢?我们只有为不同的结点指定不同的GetSection()方法了。而如何进行指定呢?我们可以写一大串的GetSectionA()、GetSectionB、GetSectionC()让它们分别去对应SectionA、SectionB、SectionC。但是我们还有更好的方法,我们可以将调用GetSection()时的结点处理逻辑委托给其他的类型去处理,而在哪里指定某个结点由某个委托程序去处理呢?自然最好还是写在配置文件中。比如,我们的XML文件是这样的: 20 30 20 /(d4)/Default.aspx /BlogDetail.aspx?year=$1 那么,我们要定义对于 forum结点和 blog结点使用不同的GetSection()方法,我们就可以这么写: 其中,configSections下的两个section结点分别用于定义对于forum和blog结点使用哪种处理方式。section结点的name属性说明是对于哪个结点,type属性说明对于该结点用什么程序来处理(当调用GetSection()方法时,会交给type所指定的类型去处理)。看到这里你应该已经明白了,上面讲述的其实正是.Net中的配置处理方法:在.Net中,配置文件实际分为了两部分,一部分是配置的实际内容,比如appSettings以及上例中的blog和forum结点;另一部分指定结点的处理程序,这些结点位于 configSections 结点下面。当你打开站点下的web.config文件,你可能看不到太多的configSections下的结点,这是因为诸如AppSettings这样的结点属于内置结点,对于它们的设置全部位于C:WINDOWSMicrosoft.NETFrameworkv2.0.50727CONFIG 下的Machine.Config文件中,以提供全局服务。(操作系统以及.Net Framework版本不同此目录的地址也不尽相同)。.Net 应用程序配置方法使用 .Net内置结点 和 .Net内置处理程序下面我们来一步步地实现.Net中的应用程序配置,首先看下对于.Net中内置的结点如何进行配置以及在程序中进行读取。创建文件夹GeneralConfig,在文件夹下新建一个站点WebSite,修改Web.Config,删除原有内容,添加如下代码(为了美观,我添加了Theme,进行了简单的样式设定,可以从文章所附的代码中进行下载): 本节我们演示如何读取appSettings以及ConnectionStrings下的配置数据。注意到Web.Config中没有configSection结点的设置,也就是并没有定义appSettings结点该如何处理。如上节所说,这是因为它们的结点处理程序定义在了machine.config中,打开machine.config,我们可以看到这样的设置: 可以看到,对于appSettings实际上是由System.Configuration.AppSettingsSection处理,而对于connectionStrings 实际上是由System.Configuration.ConnectionStringsSection 处理。另外再观察一下machine.config就会发现,处理程序分成了两种类型:一种是以Section结尾的,比如上面的这两个;还有一种是以Handler结尾的,比如:可以看到type 属性System.Configuration.NameValueFileSectionHandler是以Handler结尾的。之所以会有这样的区别,是因为.Net中对于结点有两种处理方式,一种是定义一个继承自System.Configuration.ConfigurationSection 的类,这也就是以Section结尾的类型;一种是实现System.Configuration.IConfigurationSectionHandler 接口,也就是以Handler结尾的类型。.Net Framework 2.0以后版本推荐采用继承ConfigurationSection类的方式,在本文,范例大多数使用实现IConfigurationSectionHandler接口的方式,下面也会提供一个继承ConfigurationSection类的方式作为对比。NOTE:使用私有程序集时 type通常由两部分组成,由逗号“,”分隔,前半部分是类型名称,后半部分是程序集名称。如果是公有程序集(GAC),则需要提供publicKey。好了,现在我们看一下如何在程序中读取它们。添加一个文件Basic.aspx,修改它的代码如下(只含主要代码,下同):/ Basic.aspxWebsite Information:Website Name :Version:LocalServer Connection:/ Basic.aspx.csprotected void Page_Load(object sender, EventArgs e) string siteName = ConfigurationManager.AppSettingsSiteName; string version = ConfigurationManager.AppSettingsVersion; string localConnection = ConfigurationManager.ConnectionStringsLocalServer.ConnectionString; ltrSiteName.Text = siteName; ltrVersion.Text = version; ltrLocalConnection.Text = localConnection;在浏览器中浏览,应该可以看到这样的界面:使用 自定义结点 和 .Net内置处理程序在上一节,我们使用了.Net内置的结点 appSettings 和 connectionStrings结点,并使用了 .Net 内置的处理程序。.Net 内置的处理程序定义于 machine.config中,提供全局服务,所以我们无需进行任何额外工作就可以直接使用。但是使用内置结点在很多情况下不一定方便,比如说,我们希望保存站点使用的邮件服务器的地址、用户名和密码,那么按照上面的做法,我想应该是这样的:这样的话配置及使用并不方便:首先,很明显这三个add是一组数据,但是除了凭自己的经验判断,再没有任何办法进行区分;其次,如果我们有多组服务器或者很多配置,我们需要写很长的add结点。如果我们可以自定一个结点,情况就会好很多,比如我们在Web.Config中添加一个结点: 这样看起来就好了很多,mailServer表示这是一个关于邮件服务器配置的结点,它的属性/值 分别代表存储的相应的值。以后我们在程序中进行发送邮件时可以根据这里的值来对发送邮件的对象进行参数设置。本节我们就来看下如何在web.Config中使用我们自定义的结点,但使用.Net内置的处理程序。NOTE:在web.config中,结点以及属性的命名遵循Camel命名方式,也就是首字母小写,其后的每个单词首字母大些的方式。接着在站点中添加一个 Simple.aspx 文件,打开它。此时编译器会报错,提示:“分析器错误信息: 无法识别的配置节 mailServer”。 .Net已经提供了很多内置的处理程序,为了避免发生这个错误,我们必须在configSection中指定对mailServer结点的处理程序。有时候我们希望绕过.Net的机制,直接使用System.Xml命名空间下的类来对配置文件(web.config也是标准的Xml文件)进行操作,但是因为这里会报错,所以有的人干脆就另建一个xml文件了事,然后对新建的xml文件进行操作。实际上,可以通过指定IgnoreSectionHandler 或者 IgnoreSection 处理程序的方式来进行处理,如同它们的名称所暗示的,这两个处理程序什么都不做,仅仅是让.Net 忽略我们的自定义结点。修改 web.Config ,在根节点configuration下创建configSections结点,然后再添加一个section结点,指定它的name属性值为mailServer,意为指定mailServer结点的处理程序,然后指定type为System.Configuration.IgnoreSection: 此时再次打开 Simple.aspx,编译器不再报错,由于我们什么内容也没有添加,此时会显示一个空白页面。现在,你可以采用“老办法”,编写程序去处理这个结点了,但是本文要讲述的,是一种更优雅、更.Net的方式。在本节,我们暂且不自定义处理程序,看看.Net中除了这个IgnoreSectionHandler还有什么可以利用的处理程序。在.Net中,还有一个较为常用的处理程序,就是System.Configuration.SingleTagSectionHandler,它会以Hashtable的形式返回结点的所有属性。现在我们将上面定义的configSections结点下name属性为mailServer的section结点的type属性改为System.Configuration.SingleTagSectionHandler: 然后,修改simple.aspx文件,代码如下所示:/ Simple.aspx 使用 自定义结点 和 .Net内置处理程序 MailServer Information: Address: UserName: Password: / Simple.aspx.csprotected void Page_Load(object sender, EventArgs e) / 返回一个Hashtable Hashtable mailServer = (Hashtable)ConfigurationManager.GetSection(mailServer); ltrAddress.Text = mailServeraddress.ToString(); ltrUserName.Text = mailServeruserName.ToString(); ltrPassword.Text = mailServerpassword.ToString();我们打开页面,应该会看到诸如下面这样的界面:可以看到,当我们使用System.Configuration.SingleTagSectionHandler时,调用GetSection()方法会返回一个Hashtable(当调用GetSection()方法时,会潜在地执行configSection中相应结点所指定的type类型的方法),Hashtable的key为属性的名称,Hashtable的value为属性的值。使用 自定义结点 和 自定义处理程序上面的方法虽然可行,但还存在着问题: 采用Hashtable的方法,由于key是字符串类型,除非你将结点的属性全部背过了,不然我们不得不去查看web.config文件,找到属性,然后才能书写代码去获取(比如 mailServeraddress)。而不能使用Vs提供的自动提示功能,也就是强类型访问的能力,这样的话使用起来很不方便。 假如我们的站点大了一些,只使用一个邮件服务器可能压力太大,我们需要设置多个邮件服务器,对于子域名 使用一个邮件服务器;对于 使用另一个邮件服务器,这时我们要如何设置Web.Config呢?此时,我们可能会需要下面这样结构的配置: jimmyzhang 123456 webmaster 456789 mailServerGroup 结点包含了所有关于邮件服务器的信息。它的provider属性说明邮件服务器是由哪个ISP(Internet Service Provider 互联网服务供应商)提供的,这里是中国易动网()。其下的结点mailServer是指具体的邮件服务器,client说明此邮件服务器为哪个域名提供服务,address说明邮件服务器的地址,userName和password分别为用户名和密码。此时,如果我们使用上一节的办法,将无法实现,因为它只能对单个结点进行操作,结点下不能包含子结点(文本节点也不行)。这个时候,我们最好自定义一个结点处理程序来完成。如同上面所说,此时有两种方法,一种是实现IConfigurationSectionHandler 接口,一种是继承ConfigurationSection类。我们先看如何通过实现IConfigurationSectionHandler接口的方式完成。自定义结点处理程序 实现IConfigurationSectionHandler接口IConfigurationSectionHandler 接口的定义如下:namespace System.Configuration public interface IConfigurationSectionHandler object Create(object parent, object configContext, XmlNode section); 它只要求实现一个方法:Create(),当我们在ConfigurationManager对象上调用GetSection(sectionName)方法的时候,实际上会委托给这个Create()方法进行处理。这个方法最重要的一个参数是类型为XmlNode的section,它代表着名为“sectionName”的结点。它返回一个object类型的对象,这个对象通常是我们自定义的一个关于这个结点的配置对象,对象的字段和属性映射结点的属性和文本值,来提供强类型的访问(你也可以返回一个Hashtable,这样就无需自定义类型)。NOTE:结点在在传递时有一个转换,调用GetSection()时,传递的是String类型的结点名称;而在Create()方法中,传递的是该名称的XmlNode类型的结点。我们在解决方案下面新添加一个类库项目,CustomConfig。然后在下面添加一个类文件,MailServerConfigHandler.cs。现在我们来编写代码,首先创建一个类,MailServer,这个类用于映射Web.Config中mailServerGroup结点下的mailServer子结点:public class MailServer / 存储mailServer的子结点(Address,UserName,Password)的innerText值 / 以及属性 Client 的值 private Hashtable serverNode; public MailServer() serverNode = new Hashtable(); public Hashtable ServerNode get return serverNode; public string Client get return serverNodeclient as string; public string Address get return serverNodeaddress as string; public string UserName get return serverNodeuserName as string; public string Password get return serverNodepassword as string; 注意,在MailServer类的内部,我们维护了一个Hashtable,这是因为在处理mailServerGroup结点时,我们对于它的子结点mailServer的所有属性值以及innerText都会存储在一个Hashtable中,在后面将会看到。然后我们再建一个类 MailServerConfig,让这个类继承自List,它用于映射mailServerGroup结点,我们对于mailServerGroup结点的属性以及子结点的访问,实际上均通过这个类来进行:public class MailServerConfig : List private string provider; / 对应 mailServerGroup 结点的provider 属性 public string Provider get return provider; set provider = value; 最后,到了我们对于结点的实际处理工作,创建类 MailServerConfigurationHandler,让它实现IConfigurationSectionHandler 接口:/ 自定义配置结点 mailServerGroup 的处理程序public class MailServerConfigurationHandler : IConfigurationSectionHandler / section 为 MailServerGroup 结点 public object Create(object parent, object configContext, XmlNode section) / 设置方法返回的配置对象,可以是任何类型 MailServerConfig config = new MailServerConfig(); / 获取结点的属性信息 config.Provider = section.Attributesprovider = null ? : section.Attributesprovider.Value; / 获取 MailServer 结点 foreach (XmlNode child in section.ChildNodes) MailServer server = new MailServer(); / 添加Client属性 if (child.Attributesclient != null) server.ServerNode.Add(client, child.Attributesclient.Value); / 获取MailServer下的 Name,UserName,Password 结点 foreach (XmlNode grandChild in child.ChildNodes) / 添加文本 server.ServerNode.Add(grandChild.Name, grandChild.InnerText); / 将server加入 MailServerConfig config.Add(server); return config; 我在这段代码中添加了详细的注释,这里就不再多说明了,需要注意的是它返回了一个MailServerConfig对象,在程序中,我们将通过MailServerConfig来访问结点信息。现在我们为站点添加CustomConfig的项目引用,修改Web.Config文件,添加下面代码来说明对于mailServerGroup结点的处理程序: 接下来,我们再在站点下添加一个SimpleCustom.aspx文件,使用它来测试我们的配置处理程序:/ SimpleCustom.aspx使用 自定义结点 和 自定义处理程序MailServerGroup Provider: Mail Server1(Client:) Information: Address: UserName: Password: Mail Server2(Client:) Information: Address: UserName: Password: / SimpleCustom.aspx.csprotected void Page_Load(object sender, EventArgs e) / 获取 mailServerConfig 对象 MailServerConfig mailConfig = (MailServerConfig)ConfigurationManager.GetSection(mailServerGroup); / 获取 MailServerGroup 结点的 Provider 属性 ltrServerProvider.Text = mailConfig.Provider; / 获取第一租 MailServer 数据 ltrClient1.Text = mailConfig0.Client; ltrAddress1.Text = mailConfig0.Address; ltrUserName1.Text = mailConfig0.UserName; ltrPassword1.Text = mailConfig0.Password; / 获取第二租 MailServer 数据 ltrClient2.Text = mailConfig1.Client; ltrAddress2.Text = mailConfig1.Address; ltrUserName2.Text = mailConfig1.UserName; ltrPassword2.Text = mailConfig1.Password;现在打开页面,应该可以看到下面的页面:自定义结点处理程序 继承ConfigurationSection基类除了实现IConfigurationSectionHandler接口来自定义结点处理程序,还可以通过继承ConfigurationSection基类的方式来完成,我们还以上面的例子来做说明。一般来说我们想要存储的数据可以用两种方式来存储:一种是存储到结点的属性中,一种是存储在结点的文本(InnerText)中。比如:这里是要存储的值因为一个结点可以有很多的属性,但只有一个InnerText,而在程序又要将这两种形式区别处理显然太麻烦了,所以Microsoft干脆就只使用属性存储而不使用InnerText,大家可以看一下machine.config中的配置,可曾见到过一个以InnerText来存储配置信息的?在ConfigurationSection中,也没有提供对InnerText的处理,所以对于上面的例子,我们首先要进行重新格式化,仅使用属性来存储我们的配置值。除此以外,我们还要将结点分组,对于入口结点,也就是mailServerGroup而言,这个结点组相当于它的一个属性(就好像provider一样),因为结点组包含多个结点,所以映射到面向对象的代码中,自然就成了一个集合类。所以我们需要按照这些概念将web.config中的mailServerGroup改写成下面这样: 注意,我们将mailServerGroup改成了mailServerGroup2,以免和上一节的冲突。现在我们在CustomConfig项目中添加一个文件 MailServerSection.cs,然后添加如下代码:/ MailServerSection 为入口public class MailServerSection : ConfigurationSection ConfigurationProperty
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 中药药剂学试卷试题及答案
- 机务维修面试试题及答案
- 混合设备节能策略-洞察及研究
- 建行面试题库及答案
- 安全用火考试题及答案
- 安徽辅警笔试题及答案
- 农家乐土地租赁与乡村旅游资源整合合同
- 节能减排项目担保借款协议与合同
- 2025海南公务员面试题及答案
- 灯箱广告牌广告位租赁与广告策划合同
- 大决战电影赏析课件
- 中药郁金课件
- 爆破飞石控制措施
- 《水飞蓟提取物质量要求》
- 梅毒艾滋乙肝三病
- 带状疱疹的中医护理方案
- 《病历书写基本规范》课件
- 重庆市面向西南大学定向选调2024届大学毕业生2024年国家公务员考试考试大纲历年真题3453笔试难、易错历年高频考点荟萃附带答案解析(附后)
- 知情同意书模板(新闻采访)
- 药用植物生态学药用植物与光的关系课件
- 东北财经大学网络教育成人学位英语考试往年真题试卷
评论
0/150
提交评论