.NET配置文件解析过程详解(二)
以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">进行研究和分析。