.NET配置文件解析过程详解(二)

 .NET配置文件解析过程详解(二)


在上一篇文章的基础上,我们继续我们的解析
machine.config文件内部定义的部分section handler为例,来分析各个配置节点的工厂是如何产生具体程序对象的。 


     <configuration>下的section handlers

     IgnoreSectionHandler 

     在machine.config<configSections>中有以下section是不在sectiongroup里的,换句话说这些section对应的xml节点位于配置文件根节点configuration的次级。

None.gif   < section  name ="runtime"   type ="System.Configuration.IgnoreSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"  allowLocation ="false"   />  
None.gif        
< section  name ="mscorlib"  type ="System.Configuration.IgnoreSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"  allowLocation ="false"   />  
None.gif        
< section  name ="startup"   type ="System.Configuration.IgnoreSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"  allowLocation ="false"   />  
None.gif        
< section  name ="system.runtime.remoting"  type ="System.Configuration.IgnoreSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"  allowLocation ="false"   />  
None.gif
None.gif        
< section  name ="appSettings"  type ="System.Configuration.NameValueFileSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"   />
    在这里面,runtime, remotingsection对应的handler类是IgnoreSectionHandler,难道他们用同一种工厂就可以创造出各自需要的对象?当然不是,看看SDK里对IgnoreSectionHandler的定义:
None.gif 配置系统会彻底分析配置文件以收集配置信息,并且当遇到在  < configSections >  元素节中无相应项的配置节时将引发异常。IgnoreSectionHandler 为其他系统所读取的节提供节处理程序,以防止配置文件分析异常。
   反编译 IgnoreSectionHandler 类的 Create 方法的内容为:
  
None.gif public   virtual   object  Create( object  parent,  object  configContext, XmlNode section)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif      
return null;
ExpandedBlockEnd.gif}

None.gif
     因此,我们发现 IgnoreSectionHandler 真的是什么也不做,只是为了取得对应配置节在配置文件中的合法地位,是不是有点像办个户口,占个位置啊? SDK 里所说的其他系统是什么意思呢?既然 IgnoreSectionHandler 返回的是个 null ,那其系统是怎么来通过 Getconfig 来获得需要的配置信息呢?答案是抛弃默认的 GetConfig 方法,重头再来。我们以 remoting 为例,看看他怎么来获得配置文件里的信息的。        在命名空间下System.Runtime.Remoting下有个RemotingConfiguration类,以公共静态方法Configure接收一个配置文件名,并将解析过程交给一个handler RemotingConfigHandler,这个handler并没有实现IConfigurationSectionHandler接口。RemotingConfigHandler则将实际的事务交给类RemotingXmlConfigFileData,而RemotingXmlConfigFileDataXML文件的解析过程交给RemotingXmlConfigFileParser来处理。
  
None.gif    string  text2;
None.gif      RemotingXmlConfigFileData data1 
=   new  RemotingXmlConfigFileData();
None.gif      ConfigTreeParser parser1 
=   new  ConfigTreeParser();
None.gif      ConfigNode node1 
=  parser1.Parse(filename,  " /configuration/system.runtime.remoting " );
None.gif
  由此可见 ,remoting 部分是自己重新打造了配置文件的解析过程。为什么会这样呢?为什么结构严谨的 .net 架构下会允许这样一种不统一的操作呢?这是不是一种 bad 的设计呢?这就要涉及到 system.dllmscorlib.dll 两个组件之间的关系了。 System.dll 引用了 mscorlib.dll ,也就是说 System.dll 依赖于组件 mscorlib.dll ,通用配置框架的外观类 ConfigurationSettings 处于 system.dllSystem.Configuration 命名空间下,而 RemotingConfigHandler 位于 mscorlib ,这样的结构就不能让 RemotingConfigHandler 实现 System.dll 里的 IConfigurationSectionHandler 接口了,既然某些配置程序的处理在 ConfigurationSettings 之前,那么我们对于“前辈们”的位置,我们必须认为它是合法的,然后在其位置上放一个牌子 ”occupied” -- IgnoreSectionHandler ,以通过验证。这种设计模式我认为确实值得商榷,以我目前的了解,从模式角度讲,觉得不是很合理。

    NameValueSectionHandler

      返回健值对集合对象, ConfigurationSettings.AppSettings 就是由 NameValueSectionHandler 返回的 ReadOnlyNameValueCollection 。为什么是 readonly? 原因当然不只是配置文件是只读的那么简单,因为在上一篇文章中,我有谈到解析后的对象会存在 hashtable 中,一旦程序请求同一个 tagkey 就返回同一对象,也就是解析一次,如果有删除操作,除非重启程序,否则是无法读到完整的原始配置信息的,这就涉及到我们在写自定义配置节及其 hadler 时要注意的一个地方,如果返回一个 hashtable 时,如果有删除和修改操作将会在应用程序生命周期内有效。我曾经写过一个项目,从配置文件返回一个 hashtable 储存的对象集合,为了提高效率,我会将表中某些对象 remove 掉,结果导致第一次运行一个页面和后面几次运行一个页面效果不一样的情况,害我费了很多精力找出原因。 在上一篇文章中讲过配置文件的继承,但究竟在细节上是怎么来实现的呢?我们从 section 的继承上寻找答案。实现配置信息继承的代码为:
    
None.gif  ReadOnlyNameValueCollection collection1;
None.gif      
if  (parent  ==   null )
ExpandedBlockStart.gifContractedBlock.gif      
dot.gif {
InBlock.gif            collection1 
= new ReadOnlyNameValueCollection(new CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture), new CaseInsensitiveComparer(CultureInfo.InvariantCulture));
ExpandedBlockEnd.gif      }

None.gif      
else
ExpandedBlockStart.gifContractedBlock.gif      
dot.gif {
InBlock.gif            ReadOnlyNameValueCollection collection2 
= (ReadOnlyNameValueCollection) parent;
InBlock.gif            collection1 
= new ReadOnlyNameValueCollection(collection2);
ExpandedBlockEnd.gif      }

None.gif

     NameValueSectionHandler 对节点的具体分析代码为:
   
None.gif    if  (node1.Name  ==   " add " )
ExpandedBlockStart.gifContractedBlock.gif            
dot.gif {
InBlock.gif                  
string text1 = HandlerBase.RemoveRequiredAttribute(node1, keyAttriuteName);
InBlock.gif                  
string text2 = HandlerBase.RemoveRequiredAttribute(node1, valueAttributeName, true);
InBlock.gif                  HandlerBase.CheckForUnrecognizedAttributes(node1);
InBlock.gif                  collection1[text1] 
= text2;
InBlock.gif                  
continue;
ExpandedBlockEnd.gif            }

None.gif            
if  (node1.Name  ==   " remove " )
ExpandedBlockStart.gifContractedBlock.gif            
dot.gif {
InBlock.gif                  
string text3 = HandlerBase.RemoveRequiredAttribute(node1, keyAttriuteName);
InBlock.gif                  HandlerBase.CheckForUnrecognizedAttributes(node1);
InBlock.gif                  collection1.Remove(text3);
InBlock.gif                  
continue;
ExpandedBlockEnd.gif            }

None.gif            
if  (node1.Name.Equals( " clear " ))
ExpandedBlockStart.gifContractedBlock.gif            
dot.gif {
InBlock.gif                  HandlerBase.CheckForUnrecognizedAttributes(node1);
InBlock.gif                  collection1.Clear();
InBlock.gif                  
continue;
ExpandedBlockEnd.gif            }

None.gif
    
     NameValueFileSectionHandler

    NameValueFileSectionHandlerSDK 没有相应的文档。我发现有个特点,就是很多人把这个类当成NameValueSectionHandler用,这样用似乎也没出什么问题,难道ms写了两个一样的类?非也。其实,NameValueFileSectionHandler 可以说是NameValueSectionHandler的一个升级版,升就升在 “File”上!

   我们经常抱怨配置文件越来越大了,即使是级联格式,找起东西来还是眼花,其实.net配置文件体系给我们提供了一种内置的操作来实现多个配置文件,那就是NameValueFileSectionHandlerNameValueFileSectionHandler也是返回ReadOnlyNameValueCollection。我们来看看具体的实现代码:

None.gif    object  obj1  =  parent;
None.gif      XmlNode node1 
=  section.Attributes.RemoveNamedItem( " file " );
None.gif      obj1 
=  NameValueSectionHandler.CreateStatic(obj1, section);
None.gif      
if  ((node1  ==   null ||  (node1.Value.Length  ==   0 ))
ExpandedBlockStart.gifContractedBlock.gif      
dot.gif {
InBlock.gif            
return obj1;
ExpandedBlockEnd.gif      }

None.gif

     如果该 section 没有 file 这个属性,那么其处理方式就跟 NameValueSectionHandler 一样, NameValueFileSectionHandler 调用 NameValueSectionHandler 的解析过程来取得对象。如果有 file 这个属性 NameValueFileSectionHandler 就去当前目录下或该文件的绝对路径去找到这个文件:
   
None.gif   string  text3  =  Path.GetDirectoryName(node2.Filename);
None.gif      
string  text4  =  Path.Combine(text3, text1);
None.gif

  对找到的文件,当然是 xml 解析了,取根节点作为 section 分析节点。

None.gif   ConfigXmlDocument document1  =   new  ConfigXmlDocument();
None.gif      
try
ExpandedBlockStart.gifContractedBlock.gif      
dot.gif {
InBlock.gif            document1.Load(text4);
ExpandedBlockEnd.gif      }

None.gif
   然后将新去到的 xml 节点当成 section 节点一样用 NameValueSectionHandler 解析。这样就把要写在配置文件中的 name/value 集合放到另外一个 xml 文件里去了,这样就实现了配置文件的分割,这在配置文件有很多键值对的系统中应该是比较有用的。
   
None.gif     return  NameValueSectionHandler.CreateStatic(obj1, document1.DocumentElement);
None.gif

    DictionarySectionHandler   
     NameValueSectionHandlerDictionarySectionHandler在定义配置文件的内容形式上是一样的,都是用<key><value>来设置内容的。不同的是DictionarySectionHandler比较封闭,不具有弹性,不像NameValueSectionHandler还提供给fieldhandler调用,”key”,”value”这些字符也是在属性里写死的,而且返回到C#中的类不太一样,DictionarySectionHandler返回的是一个hashtable,但还是字符串的键值对。 

   SingleTagSectionHandler 

     最简单的就是他了,就是把属性的键值对作为hashtable的键值对返回。
  

None.gif      foreach  (XmlAttribute attribute1  in  section.Attributes)
ExpandedBlockStart.gifContractedBlock.gif      
dot.gif {
InBlock.gif            hashtable1[attribute1.Name] 
= attribute1.Value;
ExpandedBlockEnd.gif      }

None.gif      
return  hashtable1;
None.gif

    在后面的文章中,我将深入<sectionGroup name="system.web">进行研究和分析。

转载于:https://www.cnblogs.com/sharpedge/archive/2005/12/04/290537.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值