在上一篇文章的基础上,我们继续我们的解析
以machine.config文件内部定义的部分section handler为例,来分析各个配置节点的工厂是如何产生具体程序对象的。
<configuration>下的section handlers
IgnoreSectionHandler
在machine.config的<configSections>中有以下section是不在sectiongroup里的,换句话说这些section对应的xml节点位于配置文件根节点configuration的次级。
< section name ="mscorlib" type ="System.Configuration.IgnoreSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowLocation ="false" />
< section name ="startup" type ="System.Configuration.IgnoreSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowLocation ="false" />
< section name ="system.runtime.remoting" type ="System.Configuration.IgnoreSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowLocation ="false" />
< section name ="appSettings" type ="System.Configuration.NameValueFileSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
{
return null;
}
RemotingXmlConfigFileData data1 = new RemotingXmlConfigFileData();
ConfigTreeParser parser1 = new ConfigTreeParser();
ConfigNode node1 = parser1.Parse(filename, " /configuration/system.runtime.remoting " );
NameValueSectionHandler
返回健值对集合对象, ConfigurationSettings.AppSettings 就是由 NameValueSectionHandler 返回的 ReadOnlyNameValueCollection 。为什么是 readonly? 原因当然不只是配置文件是只读的那么简单,因为在上一篇文章中,我有谈到解析后的对象会存在 hashtable 中,一旦程序请求同一个 tagkey 就返回同一对象,也就是解析一次,如果有删除操作,除非重启程序,否则是无法读到完整的原始配置信息的,这就涉及到我们在写自定义配置节及其 hadler 时要注意的一个地方,如果返回一个 hashtable 时,如果有删除和修改操作将会在应用程序生命周期内有效。我曾经写过一个项目,从配置文件返回一个 hashtable 储存的对象集合,为了提高效率,我会将表中某些对象 remove 掉,结果导致第一次运行一个页面和后面几次运行一个页面效果不一样的情况,害我费了很多精力找出原因。 在上一篇文章中讲过配置文件的继承,但究竟在细节上是怎么来实现的呢?我们从 section 的继承上寻找答案。实现配置信息继承的代码为:if (parent == null )
{
collection1 = new ReadOnlyNameValueCollection(new CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture), new CaseInsensitiveComparer(CultureInfo.InvariantCulture));
}
else
{
ReadOnlyNameValueCollection collection2 = (ReadOnlyNameValueCollection) parent;
collection1 = new ReadOnlyNameValueCollection(collection2);
}
NameValueSectionHandler 对节点的具体分析代码为:
{
string text1 = HandlerBase.RemoveRequiredAttribute(node1, keyAttriuteName);
string text2 = HandlerBase.RemoveRequiredAttribute(node1, valueAttributeName, true);
HandlerBase.CheckForUnrecognizedAttributes(node1);
collection1[text1] = text2;
continue;
}
if (node1.Name == " remove " )
{
string text3 = HandlerBase.RemoveRequiredAttribute(node1, keyAttriuteName);
HandlerBase.CheckForUnrecognizedAttributes(node1);
collection1.Remove(text3);
continue;
}
if (node1.Name.Equals( " clear " ))
{
HandlerBase.CheckForUnrecognizedAttributes(node1);
collection1.Clear();
continue;
}
NameValueFileSectionHandler
NameValueFileSectionHandler在SDK 中并没有相应的文档。我发现有个特点,就是很多人把这个类当成NameValueSectionHandler用,这样用似乎也没出什么问题,难道ms写了两个一样的类?非也。其实,NameValueFileSectionHandler 可以说是NameValueSectionHandler的一个升级版,升就升在 “File”上!
我们经常抱怨配置文件越来越大了,即使是级联格式,找起东西来还是眼花,其实.net配置文件体系给我们提供了一种内置的操作来实现多个配置文件,那就是NameValueFileSectionHandler。NameValueFileSectionHandler也是返回ReadOnlyNameValueCollection。我们来看看具体的实现代码:
XmlNode node1 = section.Attributes.RemoveNamedItem( " file " );
obj1 = NameValueSectionHandler.CreateStatic(obj1, section);
if ((node1 == null ) || (node1.Value.Length == 0 ))
{
return obj1;
}
如果该 section 没有 file 这个属性,那么其处理方式就跟 NameValueSectionHandler 一样, NameValueFileSectionHandler 调用 NameValueSectionHandler 的解析过程来取得对象。如果有 file 这个属性 NameValueFileSectionHandler 就去当前目录下或该文件的绝对路径去找到这个文件:
string text4 = Path.Combine(text3, text1);
对找到的文件,当然是 xml 解析了,取根节点作为 section 分析节点。
try
{
document1.Load(text4);
}
DictionarySectionHandler
NameValueSectionHandler和DictionarySectionHandler在定义配置文件的内容形式上是一样的,都是用<key><value>来设置内容的。不同的是DictionarySectionHandler比较封闭,不具有弹性,不像NameValueSectionHandler还提供给fieldhandler调用,”key”,”value”这些字符也是在属性里写死的,而且返回到C#中的类不太一样,DictionarySectionHandler返回的是一个hashtable,但还是字符串的键值对。
SingleTagSectionHandler
最简单的就是他了,就是把属性的键值对作为hashtable的键值对返回。
{
hashtable1[attribute1.Name] = attribute1.Value;
}
return hashtable1;
在后面的文章中,我将深入<sectionGroup name="system.web">进行研究和分析。