【sharpedge 】.NET配置檔案解析過程詳解

iDotNetSpace發表於2008-06-10

.NET配置檔案解析過程詳解

在我看來,WEB project的開發與WINFORM的開發最大的區別在於web的執行是在Framework上更高一層框架上執行,即ASPNET框架,程式設計師在web下的開發可以說是黑盒開發,不是讓你去定義程式入口和執行順序,而是asp.net來呼叫你的各個方法,程式設計師做的一切都是一種受控的舞蹈。就像我們呼叫nunit之類的工具來測試一個dll一樣,nunit是容器,是框架,執行哪個方法是由nunt來決定的。因此,也就有了頁面執行週期各狀態等令剛入門的程式設計師困惑不已的事,其實,究其根源,在於不瞭解容器而去使用容器。對於asp.net框架的學習,我們不妨從配置檔案開始。

對於程式開發者而言,寫配置檔案是經常性的工作,如果你寫了一個xx.config檔案,如果沒有詳盡的註釋,別人恐怕很難讀懂,沒有良好的配置架構,程式也失去了活力。在我看來,.net配置檔案的特點在於反射定義和繼承性。

我們訪問配置檔案時經常覺得配置檔案的結構不太符合我們的需要,我們需要從裡面更方便地獲得自己定義的物件,而不僅僅是keyvalue,對於自定義配置檔案的著述已有很多,在此不再描述,有興趣的朋友可以訪問http://ly4cn.cnblogs.com/archive/2005/09/06/231245.html

自定義配置節其實還是在.net配置檔案架構的應用而已,我們先來搞懂配置檔案的結構,弄清楚.net配置檔案的執行方式。下面是machine.config的一部分內容:

【sharpedge 】.NET配置檔案解析過程詳解<configSections>
【sharpedge 】.NET配置檔案解析過程詳解     
<section name="runtime"  type="System.Configuration.IgnoreSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowLocation="false" />
【sharpedge 】.NET配置檔案解析過程詳解
<sectionGroup name="system.net">
【sharpedge 】.NET配置檔案解析過程詳解            
<section name="authenticationModules" type="System.Net.Configuration.NetAuthenticationModuleHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
【sharpedge 】.NET配置檔案解析過程詳解
 sectionGroup>
【sharpedge 】.NET配置檔案解析過程詳解
configSections>
【sharpedge 】.NET配置檔案解析過程詳解

  SDK

的定義為:

【sharpedge 】.NET配置檔案解析過程詳解<section
【sharpedge 】.NET配置檔案解析過程詳解   
name="section name"
【sharpedge 】.NET配置檔案解析過程詳解   type
="configuration section handler class, assembly"
【sharpedge 】.NET配置檔案解析過程詳解   allowDefinition
="Everywhere|MachineOnly|MachineToApplication" 
【sharpedge 】.NET配置檔案解析過程詳解   allowLocation
="true|false" />
【sharpedge 】.NET配置檔案解析過程詳解

的定義為:

【sharpedge 】.NET配置檔案解析過程詳解<sectionGroup
【sharpedge 】.NET配置檔案解析過程詳解   
name="section group name"/>
【sharpedge 】.NET配置檔案解析過程詳解
sectionGroup>
【sharpedge 】.NET配置檔案解析過程詳解

  我們來看看.net框架內是如何利用這種結構的。反編譯System.dll找到GetConfig方法,在裡面我們發現實際獲取config的工作預設是由實現了IConfigurationSystemDefaultConfiguationSystem類來實現的。

【sharpedge 】.NET配置檔案解析過程詳解public static object GetConfig(string sectionName)
【sharpedge 】.NET配置檔案解析過程詳解
{
【sharpedge 】.NET配置檔案解析過程詳解      
if (!ConfigurationSettings._configurationInitialized)
【sharpedge 】.NET配置檔案解析過程詳解      
{
【sharpedge 】.NET配置檔案解析過程詳解            
lock (typeof(ConfigurationSettings))
【sharpedge 】.NET配置檔案解析過程詳解            
{
【sharpedge 】.NET配置檔案解析過程詳解                  
if ((ConfigurationSettings._configSystem == null&& !ConfigurationSettings.SetConfigurationSystemInProgress)
【sharpedge 】.NET配置檔案解析過程詳解                  
{
【sharpedge 】.NET配置檔案解析過程詳解                        ConfigurationSettings.SetConfigurationSystem(
new DefaultConfigurationSystem());
【sharpedge 】.NET配置檔案解析過程詳解                  }

【sharpedge 】.NET配置檔案解析過程詳解            }

【sharpedge 】.NET配置檔案解析過程詳解      }

【sharpedge 】.NET配置檔案解析過程詳解      
if (ConfigurationSettings._initError != null)
【sharpedge 】.NET配置檔案解析過程詳解      
{
【sharpedge 】.NET配置檔案解析過程詳解            
throw ConfigurationSettings._initError;
【sharpedge 】.NET配置檔案解析過程詳解      }

【sharpedge 】.NET配置檔案解析過程詳解      
return ConfigurationSettings._configSystem.GetConfig(sectionName);
【sharpedge 】.NET配置檔案解析過程詳解}

【sharpedge 】.NET配置檔案解析過程詳解

  我們再來看DefaultConfigurationSystem,這個類主要包含了machine.config的名稱路徑的基本資訊和一些uri操作,而實際的GetConfig的操作交給了ConfiguationRecord來處理,這個類沒有實現任何介面,可見他和DefaultConfiguration是繫結在一起的。
 1【sharpedge 】.NET配置檔案解析過程詳解internal class DefaultConfigurationSystem : IConfigurationSystem
 2【sharpedge 】.NET配置檔案解析過程詳解{
 3【sharpedge 】.NET配置檔案解析過程詳解      // Methods
 4【sharpedge 】.NET配置檔案解析過程詳解      internal DefaultConfigurationSystem();
 5【sharpedge 】.NET配置檔案解析過程詳解      object IConfigurationSystem.GetConfig(string configKey);
 6【sharpedge 】.NET配置檔案解析過程詳解      void IConfigurationSystem.Init();
 7【sharpedge 】.NET配置檔案解析過程詳解
 8【sharpedge 】.NET配置檔案解析過程詳解      // Properties
 9【sharpedge 】.NET配置檔案解析過程詳解      internal static Uri AppConfigPath get; }
10【sharpedge 】.NET配置檔案解析過程詳解      internal static string MachineConfigurationFilePath get; }
11【sharpedge 】.NET配置檔案解析過程詳解      internal static string MsCorLibDirectory get; }
12【sharpedge 】.NET配置檔案解析過程詳解
13【sharpedge 】.NET配置檔案解析過程詳解      // Fields
14【sharpedge 】.NET配置檔案解析過程詳解      private ConfigurationRecord _application;
15【sharpedge 】.NET配置檔案解析過程詳解      private const string ConfigExtension = "config";
16【sharpedge 】.NET配置檔案解析過程詳解      private const string MachineConfigFilename = "machine.config";
17【sharpedge 】.NET配置檔案解析過程詳解      private const string MachineConfigSubdirectory = "Config";
18【sharpedge 】.NET配置檔案解析過程詳解      private const int MaxPathSize = 0x400;
19【sharpedge 】.NET配置檔案解析過程詳解}

20【sharpedge 】.NET配置檔案解析過程詳解

事實上所有的配置檔案的分析和獲取都是在ConfiguationRecord裡實現的,作為配置檔案分析的第一步,正如我們經常做的一樣->載入一個配置檔案,這個方法公開為 Load(filename)。DefaultConfiguationSystem的Init()方法中用machine.config建立了一個 ConfiguationRecord物件,並將其作為父物件傳遞給當前程式的ConfiguationRecord物件,當然前提是當前程式有配置檔案,比如myapp.config,然後再載入當前程式的配置檔案,從而實現配置檔案的繼承。
【sharpedge 】.NET配置檔案解析過程詳解void IConfigurationSystem.Init()
【sharpedge 】.NET配置檔案解析過程詳解
{
【sharpedge 】.NET配置檔案解析過程詳解      
lock (this)
【sharpedge 】.NET配置檔案解析過程詳解      
{
【sharpedge 】.NET配置檔案解析過程詳解            
if (this._application == null)
【sharpedge 】.NET配置檔案解析過程詳解            
{
【sharpedge 】.NET配置檔案解析過程詳解                  ConfigurationRecord record1 
= null;
【sharpedge 】.NET配置檔案解析過程詳解                  
string text1 = DefaultConfigurationSystem.MachineConfigurationFilePath;
【sharpedge 】.NET配置檔案解析過程詳解                  Uri uri1 
= DefaultConfigurationSystem.AppConfigPath;
【sharpedge 】.NET配置檔案解析過程詳解                  
this._application = record1 = new ConfigurationRecord();
【sharpedge 】.NET配置檔案解析過程詳解                  
bool flag1 = record1.Load(text1);
【sharpedge 】.NET配置檔案解析過程詳解                  
if (!flag1 || (uri1 == null))
【sharpedge 】.NET配置檔案解析過程詳解                  
{
【sharpedge 】.NET配置檔案解析過程詳解                        
return;
【sharpedge 】.NET配置檔案解析過程詳解                  }

【sharpedge 】.NET配置檔案解析過程詳解                  
this._application = new ConfigurationRecord(record1);
【sharpedge 】.NET配置檔案解析過程詳解                  
this._application.Load(uri1.ToString());
【sharpedge 】.NET配置檔案解析過程詳解            }

【sharpedge 】.NET配置檔案解析過程詳解      }

【sharpedge 】.NET配置檔案解析過程詳解}

【sharpedge 】.NET配置檔案解析過程詳解 
【sharpedge 】.NET配置檔案解析過程詳解

現在我們可以專注於ConfiguationRecord的具體實現了,Load方法中得到一個XmlTextWriter,並執行.ScanFactoriesRecursive和ScanSectionsRecursive方法。

【sharpedge 】.NET配置檔案解析過程詳解 reader1 = ConfigurationRecord.OpenXmlTextReader(filename);
【sharpedge 】.NET配置檔案解析過程詳解            
if (reader1 != null)
【sharpedge 】.NET配置檔案解析過程詳解            
{
【sharpedge 】.NET配置檔案解析過程詳解                  
this.ScanFactoriesRecursive(reader1);
【sharpedge 】.NET配置檔案解析過程詳解                  
if (reader1.Depth == 1)
【sharpedge 】.NET配置檔案解析過程詳解                  
{
【sharpedge 】.NET配置檔案解析過程詳解                        
this.ScanSectionsRecursive(reader1, null);
【sharpedge 】.NET配置檔案解析過程詳解                  }

【sharpedge 】.NET配置檔案解析過程詳解                  
return true;
【sharpedge 】.NET配置檔案解析過程詳解            }

【sharpedge 】.NET配置檔案解析過程詳解

 ScanFactoriesRecursive方法會呼叫他的一個過載方法來解析中的< sectionGroup>,

,,,我們寫配置檔案時大小寫可不能寫錯哦,.NET沒有做toslower之類的轉換,直接就是 “== “。在這個方法里程式會將解析得到的sectiongroup以key=tagkey,value= ConfigurationRecord.GroupSingleton的方式存到EnsureFactories裡,將section以key= tagkey,value=typestring的方式儲存,值得注意的是,這裡並沒有建立實現 IConfigurationSectionHandler的例項物件,而是將其型別名(比如:字串” system.Configuration.NameValueSectionHandler”)作為值到EnsureFactories,等到後面 GetConfig的時候再來反射建立。則存為 ConfigurationRecord.RemovedFactorySingleton。就清空 EnsureFactories。這裡的tagkey是各級name的組合,比如”mygroup/mysection”這樣以分隔符”/”組合的形式。應該客觀地說這部分程式碼用了很多goto語句,可讀性不是太好,但這樣寫也確實沒有什麼問題。

【sharpedge 】.NET配置檔案解析過程詳解   this.CheckRequiredAttribute(text3, "name", reader);
【sharpedge 】.NET配置檔案解析過程詳解            
this.CheckRequiredAttribute(text4, "type", reader);
【sharpedge 】.NET配置檔案解析過程詳解            
this.VerifySectionName(text3, reader);
【sharpedge 】.NET配置檔案解析過程詳解            
string text5 = ConfigurationRecord.TagKey(configKey, text3);
【sharpedge 】.NET配置檔案解析過程詳解            
if (this.HaveFactory(text5) != ConfigurationRecord.HaveFactoryEnum.NotFound)
【sharpedge 】.NET配置檔案解析過程詳解            
{
【sharpedge 】.NET配置檔案解析過程詳解                  objArray1 
= new object[] { text3 } ;
【sharpedge 】.NET配置檔案解析過程詳解                  
throw this.BuildConfigError(SR.GetString("Tag_name_already_defined", objArray1), reader);
【sharpedge 】.NET配置檔案解析過程詳解            }

【sharpedge 】.NET配置檔案解析過程詳解            
this.EnsureFactories[text5] = text4;
【sharpedge 】.NET配置檔案解析過程詳解            
goto Label_02B6;
【sharpedge 】.NET配置檔案解析過程詳解

ScanSectionsRecursive方法會解析配置檔案裡的section例項,並將其tagkey儲存到Hashtable _unevaluatedSections中,表示尚未evaluated的configkey的集合,可見section例項物件的建立和 handler一樣,都是fetch when need。在後面的操作Getconfig中會使用他。

【sharpedge 】.NET配置檔案解析過程詳解    if (this._unevaluatedSections == null)
【sharpedge 】.NET配置檔案解析過程詳解            
{
【sharpedge 】.NET配置檔案解析過程詳解                  
this._unevaluatedSections = new Hashtable();
【sharpedge 】.NET配置檔案解析過程詳解            }

【sharpedge 】.NET配置檔案解析過程詳解     &

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-343236/,如需轉載,請註明出處,否則將追究法律責任。

相關文章