google Python linux 开源 Windows mysql php shell 云计算 编程 程序员 java Ubuntu 微软 Firefox nginx apache centos wordpress Android

揭開.NET 2.0配置之謎(二)

聲明:此文是譯文,原文是Jon Rista,Unraveling the Mysteries of .NET 2.0 Configuration,由於這篇文章比較長,所以我就分為幾部分來翻譯,這是此譯文的第二部分。

ps:首先說聲sorry,發布的揭開.NET2.0配置之謎(一)排版錯亂給大家閱讀帶來了不便,不過現在已經修正。原因是我用Windows live writer發布譯文之後,用博客園中的TinyMCE編輯了一下,保存之後就出現了排版錯亂問題。

let's go on!

5、添加自定義元素

默認情況下,自定義配置節中所有的配置屬性(properties)在.config文件中被表示成屬性(attributes)。這並不總是必然的,然而,一個更復雜XML結構,由屬性(attributes)和元素(elements)混合組成的,是需要的。不要怕:.NET的配置系統完全支持自定義配置元素,他們的屬性(properties)可以是屬性(attributes)或者多個嵌套元素。要創建自定義配置元素,簡單地寫一個類繼承自ConfigurationElement而不是ConfigurationSection。配置元素的執行細節跟配置節一樣,不同之處是元素必須嵌套在配置節中。

讓我們繼續,嵌套一個自定義元素在ExampleSection中。讓我們這個嵌套元素存儲一個DateTime值和一個整數值。創建這個類的代碼如下所示:


 
  1. #region Using Statements  
  2. using System;  
  3. using System.Configuration;  
  4. #endregion  
  5.  
  6. namespace Examples.Configuration  
  7. {  
  8.     /// <summary>  
  9.     /// An example configuration element class.  
  10.     /// </summary>  
  11.     public class NestedElement: ConfigurationElement  
  12.     {  
  13.         #region Constructors  
  14.         /// <summary>  
  15.         /// Predefines the valid properties and prepares  
  16.         /// the property collection.  
  17.         /// </summary>  
  18.         static NestedElement()  
  19.         {  
  20.             // Predefine properties here  
  21.             s_propDateTime = new ConfigurationProperty(  
  22.                 "dateTimeValue",  
  23.                 typeof(DateTime),  
  24.                 null,  
  25.                 ConfigurationPropertyOptions.IsRequired  
  26.             );  
  27.  
  28.             s_propInteger = new ConfigurationProperty(  
  29.                 "integerValue",  
  30.                 typeof(int),  
  31.                 0,  
  32.                 ConfigurationPropertyOptions.IsRequired  
  33.             );  
  34.  
  35.             s_properties = new ConfigurationPropertyCollection();  
  36.               
  37.             s_properties.Add(s_propDateTime);  
  38.             s_properties.Add(s_propInteger);  
  39.         }  
  40.         #endregion  
  41.  
  42.         #region Static Fields  
  43.         private static ConfigurationProperty s_propDateTime;  
  44.         private static ConfigurationProperty s_propInteger;  
  45.  
  46.         private static ConfigurationPropertyCollection s_properties;  
  47.         #endregion  
  48.  
  49.            
  50.         #region Properties  
  51.         /// <summary>  
  52.         /// Gets the DateTimeValue setting.  
  53.         /// </summary>  
  54.         [ConfigurationProperty("dateTimeValue", IsRequired=true)]  
  55.         public DateTime StringValue  
  56.         {  
  57.             get { return (DateTime)base[s_propDateTime]; }  
  58.         }  
  59.  
  60.         /// <summary>  
  61.         /// Gets the IntegerValue setting.  
  62.         /// </summary>  
  63.         [ConfigurationProperty("integerValue")]  
  64.         public int IntegerValue  
  65.         {  
  66.             get { return (int)base[s_propInteger]; }  
  67.         }  
  68.  
  69.         /// <summary>  
  70.         /// Override the Properties collection and return our custom one.  
  71.         /// </summary>  
  72.         protected override ConfigurationPropertyCollection Properties  
  73.         {  
  74.             get { return s_properties; }  
  75.         }  
  76.         #endregion  
  77.     }  

将这个元素加到我们之前创建的ExampleSection中,就像定义一个新属性一样简单。下面展示了添加一个嵌套元素的必要代码:


 
  1. public class ExampleSection: ConfigurationSection  
  2.     {  
  3.         #region Constructors  
  4.         /// <summary>  
  5.         /// Predefines the valid properties and prepares  
  6.         /// the property collection.  
  7.         /// </summary>  
  8.         static ExampleSection()  
  9.         {  
  10.             // Create other properties...  
  11.  
  12.             s_propElement = new ConfigurationProperty(  
  13.                 "nestedElement",  
  14.                 typeof(NestedElement),  
  15.                 null,  
  16.                 ConfigurationPropertyOptions.IsRequired  
  17.             );  
  18.  
  19.             s_properties = new ConfigurationPropertyCollection();  
  20.               
  21.             // Add other properties...  
  22.             s_properties.Add(s_propElement);  
  23.         }  
  24.         #endregion  
  25.  
  26.         #region Static Fields  
  27.         private static ConfigurationProperty s_propElement;  
  28.         // Other static fields...  
  29.         #endregion  
  30.  
  31.            
  32.         #region Properties  
  33.         // ...  
  34.  
  35.         /// <summary>  
  36.         /// Gets the NestedElement element.  
  37.         /// </summary>  
  38.         [ConfigurationProperty("nestedElement")]  
  39.         public NestedElement Nested  
  40.         {  
  41.             get { return (NestedElement)base[s_propElement]; }  
  42.         }  
  43.  
  44.         // ...  
  45.         #endregion  
  46.     } 

最后,在我们的XML配置文件中使用这个元素只需要简单地在<example>标记中添加<nestedElement>标记。值得注意的是,只能有一个nestedElement实例在example中。这种方式创建的嵌套元素,不允许有类似命名的元素集合。它允许一个特定元素的单个实例,在自定义节的一个特定的嵌套深度。下一节将讲在一个配置节中定义元素集合。完整的App.config文件应该像下面这样:


 
  1. <configuration> 
  2.   <configSections> 
  3.     <section name="example" type="Examples.Configuration.ExampleSection,   
  4.                                   Examples.Configuration" /> 
  5.   </configSections> 
  6.  
  7.   <example 
  8.     stringValue="A sample string value." 
  9.     boolValue="true" 
  10.     timeSpanValue="5:00:00" 
  11.   > 
  12.     <nestedElement 
  13.       dateTimeValue="10/16/2006" 
  14.       integerValue="1" 
  15.     /> 
  16.   </example> 
  17. </configuration> 

使用新的套元素又是非常的简单,因为Nested属性(property)将暴露给我们的前面例子中使用的节变量:


 
  1. private string m_string;  
  2. private bool m_bool;  
  3. private TimeSpan m_timespan;  
  4. private DateTime m_datetime;  
  5. private int m_int;  
  6.  
  7. void GetExampleSettings()  
  8. {  
  9.     ExampleSection section = ConfigurationManager.GetSection("example")   
  10.                              as ExampleSection;  
  11.     if (section != null)  
  12.     {  
  13.         m_string = section.StringValue;  
  14.         m_bool = section.BooleanValue;  
  15.         m_timespan = section.TimeSpanValue;  
  16.         m_datetime = section.Nested.DateTimeValue;  
  17.         m_int = section.Nested.IntegerValue;  
  18.     }  

每个配置节可以由任意数量的属性(attributes)和元素(elements)组成,元素可以嵌套的任意的深度以满足应用程序。相对于其他XML用法,这总是一个好主意,符合相同的XML自定义配置节的最佳做法。作为一般规则,数据集或大量的信息不应该保存在自定义配置节。我们将在高级配置主题那节讨论原因。这些“配置”部分,应该用于存储结构化的应用配置信息。

6、添加元素集合

在上一节,我们在一个配置节元素中创建一个嵌套元素。嵌套的元素仅限于只有一个实例,且必须出现在指定的元素中。创建元素集合或元素列表需要不同的和稍微复杂的方法。在配置文件中要创建一个配置元素集合或列表,你必须要创建一个类继承自ConfigurationElementCollection。几种集合可以被创建,两个主要集合类型是BasicMapAddRemoveClearMap

任何用过<appSettings>配置节的人都会熟悉AddRemoveClearMap的集合类型。AddRemoveClearMap是ASP.NET web.config文件中的一个级联集合。级联集合允许元素在web站点路径级添加,移除或清除在低级别的应用程序级。此外,在低级别添加的任何新的唯一元素都将和高级别的所有元素合并。请参阅附录A,更多细节关于配置如何级联作用。Basic map更为严格,但允许其他不是“add”名称的元素添加到一个集合中。一个Basic map的别的元素名称的例子是System.Web的<customError>节,它支持一个<error>元素的集合。

由于AddRemoveClearMap集合是默认类型,让我们创建一个并将它加到我们之前的配置节例子中。创建一个元素集合的代码比配置节或单个元素要稍微复杂一些,但是整体来说仍然非常简单。下面的元素集合代码遵循一个标准模式,.NET 2.0框架中大部分元素集合都是它:


 
  1. [ConfigurationCollection(typeof(ThingElement),  
  2.     CollectionType=ConfigurationElementCollectionType.AddRemoveClearMap)]  
  3. public class ExampleThingElementCollection: ConfigurationElementCollection  
  4. {  
  5.     #region Constructors  
  6.     static ExampleThingElementCollection()  
  7.     {  
  8.         m_properties = new ConfigurationPropertyCollection();  
  9.     }  
  10.  
  11.     public ExampleThingElementCollection()  
  12.     {  
  13.     }  
  14.     #endregion  
  15.  
  16.     #region Fields  
  17.     private static ConfigurationPropertyCollection m_properties;  
  18.     #endregion  
  19.  
  20.     #region Properties  
  21.     protected override ConfigurationPropertyCollection Properties  
  22.     {  
  23.         get { return m_properties; }  
  24.     }  
  25.       
  26.     public override ConfigurationElementCollectionType CollectionType  
  27.     {  
  28.         get { return ConfigurationElementCollectionType.AddRemoveClearMap; }  
  29.     }  
  30.     #endregion  
  31.  
  32.     #region Indexers  
  33.     public ThingElement this[int index]  
  34.     {  
  35.         get { return (ThingElement)base.BaseGet(index); }  
  36.         set 
  37.         {  
  38.             if (base.BaseGet(index) != null)  
  39.             {  
  40.                 base.BaseRemoveAt(index);  
  41.             }  
  42.             base.BaseAdd(index, value);  
  43.         }  
  44.     }  
  45.  
  46.     public ThingElement this[string name]  
  47.     {  
  48.         get { return (ThingElement)base.BaseGet(name); }  
  49.     }  
  50.     #endregion  
  51.       
  52.     #region Overrides  
  53.     protected override ConfigurationElement CreateNewElement()  
  54.     {  
  55.         return new ThingElement();  
  56.     }  
  57.  
  58.     protected override object GetElementKey(ConfigurationElement element)  
  59.     {  
  60.         return (element as ThingElement).Name;  
  61.     }  
  62.     #endregion  

一般都需要提供一个通过数字索引的索引器。通过一个元素的关键字索引的索引器也是非常方便的。在这个例子中,关键字是一个字符串名称。两个重写方法CreateNewElementGetElementKey,对于确保你的集合功能正常非常重要。CreateNewElement有两个重载的方法,一个没有参数,另一个以一个元素名作参数,如果你重载了默认的AddRemoveClearMap行为。更多的关于这个将在高级主题那节讨论。默认,CreateNewElement(string elementName)重载调用CreateNewElement(),所以他并非总是需要重载的。GetElementKey返回指定的配置元素的值,而且返回值唯一标识他。在我们的例子中,关键字是Name属性(property),将在我们的ThingElement定义。最后,你可能已经注意到属性(Properties)集合被重写了。这个原因不是很明显,除非你深入研究.NET框架的源代码,但是可以说这是一个性能优化。

我们的集合并没有完全完成,我们需要收集一些东西。对于我们的例子,就是ThingElement。这是另外一个ConfigurationElement类,类似于我们的之前的NestedElement。


 
  1. public class ThingElement: ConfigurationElement  
  2. {  
  3.         #region Constructors  
  4.         /// <summary>  
  5.         /// Predefines the valid properties and prepares  
  6.         /// the property collection.  
  7.         /// </summary>  
  8.         static ThingElement()  
  9.         {  
  10.             // Predefine properties here  
  11.             s_propName = new ConfigurationProperty(  
  12.                 "name",  
  13.                 typeof(string),  
  14.                 null,  
  15.                 ConfigurationPropertyOptions.IsRequired  
  16.             );  
  17.  
  18.             s_propType = new ConfigurationProperty(  
  19.                 "type",  
  20.                 typeof(string),  
  21.                 "Normal",  
  22.                 ConfigurationPropertyOptions.None  
  23.             );  
  24.  
  25.             s_propColor = new ConfigurationProperty(  
  26.                 "color",  
  27.                 typeof(string),  
  28.                 "Green",  
  29.                 ConfigurationPropertyOptions.None  
  30.             );  
  31.  
  32.             s_properties = new ConfigurationPropertyCollection();  
  33.               
  34.             s_properties.Add(s_propName);  
  35.             s_properties.Add(s_propType);  
  36.             s_properties.Add(s_propColor);  
  37.         }  
  38.         #endregion  
  39.  
  40.         #region Static Fields  
  41.         private static ConfigurationProperty s_propName;  
  42.         private static ConfigurationProperty s_propType;  
  43.         private static ConfigurationProperty s_propColor;  
  44.  
  45.         private static ConfigurationPropertyCollection s_properties;  
  46.         #endregion  
  47.  
  48.            
  49.         #region Properties  
  50.         /// <summary>  
  51.         /// Gets the Name setting.  
  52.         /// </summary>  
  53.         [ConfigurationProperty("name", IsRequired=true)]  
  54.         public string Name  
  55.         {  
  56.             get { return (string)base[s_propName]; }  
  57.         }  
  58.  
  59.         /// <summary>  
  60.         /// Gets the Type setting.  
  61.         /// </summary>  
  62.         [ConfigurationProperty("type")]  
  63.         public string Type  
  64.         {  
  65.             get { return (string)base[s_propType]; }  
  66.         }  
  67.  
  68.         /// <summary>  
  69.         /// Gets the Type setting.  
  70.         /// </summary>  
  71.         [ConfigurationProperty("color")]  
  72.         public string Color  
  73.         {  
  74.             get { return (string)base[s_propColor]; }  
  75.         }  
  76.  
  77.         /// <summary>  
  78.         /// Override the Properties collection and return our custom one.  
  79.         /// </summary>  
  80.         protected override ConfigurationPropertyCollection Properties  
  81.         {  
  82.             get { return s_properties; }  
  83.         }  
  84.         #endregion  

我们的ThingElement很简单,只提供了一个名称、类型和颜色。现在你应该注意到,至此我们的配置类中我们已经重写了Properties集合。这不是一个不要的步骤,但它可以提高配置节的性能和效率。更多详细介绍在高级主题那节。我们可以通过添加另一个ConfigurationProperty使这个集合在我们的ExampleSection中可以访问,实现方法和NestedElement一样。只是这次,用ExampleThingElementCollection替换了NestedElement。用“Thing”命名元素,现在由我们的代码支持的例子如下:


 
  1. <configuration> 
  2.   <configSections> 
  3.     <section name="example" type="Examples.Configuration.ExampleSection,   
  4.                                      Examples.Configuration" /> 
  5.   </configSections> 
  6.  
  7.   <example 
  8.     stringValue="A sample string value." 
  9.     boolValue="true" 
  10.     timeSpanValue="5:00:00" 
  11.   > 
  12.     <nestedElement 
  13.       dateTimeValue="10/16/2006" 
  14.       integerValue="1" 
  15.     /> 
  16.     <things> 
  17.       <add name="slimy" type="goo" /> 
  18.       <add name="metal" type="metal" color="silver" /> 
  19.       <add name="block" type="wood" color="tan" /> 
  20.     </things> 
  21.   </example> 
  22. </configuration> 

7、高级元素集合

在上一节中,您学习了如何创建一个标准的AddRemoveClearMap集合类型,它也是默认的类型。总共有四个类型的集合(有两种类型,每种类型有两种版本):AddRemoveClearMap 和 AddRemoveClearMapAlternate以及BasicMap 和 BasicMapAlternate。从上一节,我们知道AddRemoveClearMap是如何其作用的。BasicMap 限制比AddRemoveClearMap 强,它不允许较低级的web.config修改从较高级的web.config继承的任何东西,但它允许除<add>名称之外的元素。两种主要类型的替换版本只是对元素的排序不同,添加继承的元素,将它们他在最后。

译注:ConfigurationElementCollectionType 枚举,指定 ConfigurationElementCollectionType 对象的类型,包含以下4种类型:

BasicMap
此类型的集合包含应用于指定的级别(由这些元素指定)和所有子级别的元素。子级别不能修改由此类型的父元素指定的属性。

AddRemoveClearMap
ConfigurationElementCollection 的默认类型。此类型的集合包含可在配置文件的层次结构中进行合并的元素。在这类层次结构的任何特定级别中,均可使用 add、remove 和 clear 指令修改任何继承的属性和指定新的属性。

BasicMapAlternate
除了使 ConfigurationElementCollection 对象对其内容进行排序以将继承的元素排列在最后外,此类型与 BasicMap 相同。

AddRemoveClearMapAlternate
除了使 ConfigurationElementCollection 对象对其内容进行排序以将继承的元素排列在最后外,此类型与 AddRemoveClearMap 相同。

在前面的例子里,我们创建了一个集合表示things,而且每一个thing都是通过<add>元素来添加的。对于我们的目的,完全支持级联联合可能是没有必要的,而且用<thing>作为元素的名字比<add>好。我们可以使用很多种方法来完成这个,但是我们将使用最常见的修改我们原来的ThingElementCollection类为BasicMap 并使用元素名字<thing>:


 
  1. [ConfigurationCollection(typeof(ThingElement), AddItemName="thing",   
  2.       CollectionType=ConfigurationElementCollectionType.BasicMap)]  
  3. public class ExampleThingElementCollection: ConfigurationElementCollection  
  4. {  
  5.     #region Constructors  
  6.     // ...  
  7.     #endregion  
  8.  
  9.     #region Fields  
  10.     // ...  
  11.     #endregion  
  12.  
  13.     #region Properties  
  14.     // ...  
  15.  
  16.     public override ConfigurationElementCollectionType CollectionType  
  17.     {  
  18.         get { return ConfigurationElementCollectionType.BasicMap; }  
  19.     }  
  20.  
  21.     protected override string ElementName  
  22.     {  
  23.         get { return "thing"; }  
  24.     }  
  25.     #endregion  
  26.  
  27.     #region Indexers  
  28.     // ...  
  29.     #endregion  
  30.  
  31.     #region Methods  
  32.     // ...  
  33.     #endregion  
  34.       
  35.     #region Overrides  
  36.     // ...  
  37.     #endregion  

这些简单的修改将更新我们的集合类为BasicMap ,这将使得在.config文件中可以使用元素<thing>添加新项,而不是<add>。现在我们可以这样修改我们的配置文件,比以前的版本更漂亮、更清楚:


 
  1. <configuration> 
  2.   <configSections> 
  3.     <section name="example" type="Examples.Configuration.ExampleSection,  
  4.                                      Examples.Configuration" /> 
  5.   </configSections> 
  6.  
  7.   <example 
  8.     stringValue="A sample string value." 
  9.     boolValue="true" 
  10.     timeSpanValue="5:00:00" 
  11.   > 
  12.     <nestedElement 
  13.       dateTimeValue="10/16/2006" 
  14.       integerValue="1" 
  15.     /> 
  16.     <things> 
  17.       <thing name="slimy" type="goo" /> 
  18.       <thing name="metal" type="metal" color="silver" /> 
  19.       <thing name="block" type="wood" color="tan" /> 
  20.     </things> 
  21.   </example> 
  22. </configuration> 

有时候,当我们有一个层次结构的配置,而且设置级联从一个父web.config到子web.config,我们需要控制那些元素显示在集合的前面。默认,所有元素以继承的顺序。当有多个web.config文件合并时,这种顺序不是特别好定义。通过使用替换的集合类型(译注:即BasicMapAlternateAddRemoveClearMapAlternate),我们可以控制迫使所以继承的元素被列在最后。级联三个web.config文件将以读取文件的顺序列出所有项,以最低级的web.config开始,随后是他的父web.config们,最后是根web.config。BasicMapAlternateAddRemoveClearMapAlternate都是这种方式,而且警告添加时修改父级别的web.config的项。

8、自定义配置节组

根据你致力于的项目类型或者特定于你的应用程序的配置需求,你可能会觉得使用配置节组更有用。.NET 2.0提供了便利的配置功能来完成这事,之前我们讨论的ASP.NET的<system.web>配置组就是。创建一个配置节组比创建一个配置节更简单,但是使用和访问他们呢稍微复杂一些。假定我们有两个配置节类叫做ExampleSection 和AnotherSection,我们可以像这样写成一个配置组:


 
  1. public sealed class ExampleSectionGroup: ConfigurationSectionGroup  
  2. {  
  3.     #region Constructors  
  4.     public ExampleSectionGroup()  
  5.     {  
  6.     }  
  7.     #endregion  
  8.  
  9.     #region Properties  
  10.     [ConfigurationProperty("example")]  
  11.     public ExampleSection Example  
  12.     {  
  13.         get { return (ExampleSection)base.Sections["example"]; }  
  14.     }  
  15.  
  16.     [ConfigurationProperty("another")]  
  17.     public AnotherSection Another  
  18.     {  
  19.         get { return (AnotherSection)base.Sections["another"]; }  
  20.     }  
  21.     #endregion  

一旦我们有了节组代码,我们需要在.config文件中定义它。和定义一个一般的节类似,只是增加了层次级别。值得注意的是,ExampleSection 和AnotherSection现在必须作为我们配置组的子节点定义:


 
  1. <configuration> 
  2.   <configSections> 
  3.     <sectionGroup name="example.group"   
  4.         type="Examples.Configuration.ExampleSectionGroup,   
  5.               Examples.Configuration"> 
  6.       <section name="example" type="Examples.Configuration.ExampleSection,  
  7.                                        Examples.Configuration" /> 
  8.       <section name="another" type="Examples.Configuration.AnotherSection,  
  9.                                        Examples.Configuration" /> 
  10.     </sectionGroup> 
  11.   </configSections> 
  12.  
  13.   <example.group> 
  14.  
  15.     <example 
  16.       stringValue="A sample string value." 
  17.       boolValue="true" 
  18.       timeSpanValue="5:00:00" 
  19.     > 
  20.       <nestedElement 
  21.         dateTimeValue="10\16\2006" 
  22.         integerValue="1" 
  23.       /> 
  24.       <things> 
  25.         <thing name="slimy" type="goo" /> 
  26.         <thing name="metal" type="metal" color="silver" /> 
  27.         <thing name="block" type="wood" color="tan" /> 
  28.       </things> 
  29.     </example> 
  30.  
  31.     <another value="someValue" /> 
  32.  
  33.   </example.group> 

这个配置节组做了这些,使两个配置节在一个组。此外,它提供了一个访问这些节的中心点。一旦我们有一个引用指向我们的ConfigurationSectionGroup对象,我们可以访问ExampleSection 和AnotherSection,而不用再次调用ConfigurationManager.GetSection()。但是,获取最初的引用指向我们的ExampleSectionGroup并不和获取一个单独的节那样简单。专研.NET 2.0深入一点,我们将发现Configuration类。这个类直接表示一个应用程序定义在它的.config文件中的配置。跟ConfigurationManager类一样,Configuration有一个GetSection()方法,以及附加了GetSectionGroup()方法。我们可以访问配置节组和里面的配置节,例如:


 
  1. private string m_string;  
  2. private bool m_bool;  
  3. private TimeSpan m_timespan;  
  4. private DateTime m_datetime;  
  5. private int m_int;  
  6.  
  7. void GetExampleSettings()  
  8. {  
  9.     Configuration config =   
  10.       ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);  
  11.     ExampleSectionGroup group = config.GetSectionGroup("example.group")   
  12.                                 as ExampleSectionGroup;  
  13.  
  14.     ExampleSection section = group.Example;  
  15.     m_string = section.StringValue;  
  16.     m_bool = section.BooleanValue;  
  17.     m_timespan = section.TimeSpanValue;  
  18.     m_datetime = section.Nested.DateTimeValue;  
  19.     m_int = section.Nested.IntegerValue;  
  20.  
  21.     AnotherSection section2 = group.Another;  

虽然上面的代码不是很复杂,要求一个Configuration对象来获得GetSectionGroup()方法不是很明显。一旦我们有一个Configuration对象,然而,你会发现一些他的额外有用的功能。在下一节中,我们将讨论用Configuration对象来将修改保存回配置文件,只要支持保存。

9、保存配置更改

到目前为止,我们已经研究了使用.NET 2.0的配置功能来定义和加载配置设置。对于许多应用程序来说,这是不够的。和使用一样,有许多时候必须保存配置。在上一节中,我们使用了Configuration对象,它提供给开发者一种将修改编程式地保存回配置节。唯一的先决条件就是配置对象允许有变更。让我们回顾一下原来的ExampleSection类,并使它可修改:


 
  1. #region Properties  
  2.         /// <summary>  
  3.         /// Gets the StringValue setting.  
  4.         /// </summary>  
  5.         [ConfigurationProperty("stringValue", IsRequired=true)]  
  6.         public string StringValue  
  7.         {  
  8.             get { return (string)base[s_propString]; }  
  9.             set { base[s_propString] = value; }  
  10.             // Allows setting to be changed  
  11.         }  
  12.  
  13.         /// <summary>  
  14.         /// Gets the BooleanValue setting.  
  15.         /// </summary>  
  16.         [ConfigurationProperty("boolValue")]  
  17.         public bool BooleanValue  
  18.         {  
  19.             get { return (bool)base[s_propBool]; }  
  20.             set { base[s_propBool] = value; }  
  21.             // Allows setting to be changed  
  22.         }  
  23.  
  24.         /// <summary>  
  25.         /// Gets the TimeSpanValue setting.  
  26.         /// </summary>  
  27.         [ConfigurationProperty("timeSpanValue")]  
  28.         public TimeSpan TimeSpanValue  
  29.         {  
  30.             get { return (TimeSpan)base[s_propTimeSpan]; }  
  31.             set { base[s_propTimeSpan] = value; }  
  32.             // Allows setting to be changed  
  33.         }  
  34.  
  35.         /// <summary>  
  36.         /// Override the Properties collection and return our custom one.  
  37.         /// </summary>  
  38.         public override ConfigurationPropertyCollection Properties  
  39.         {  
  40.             get { return s_properties; }  
  41.         }  
  42.         #endregion 

正如你所看到的,更改基本的上由.NET 2.0提供的对象模型配置。简单地添加setters到配置属性上,允许他们在代码中被修改。ConfigurationElement,这是最终在每个配置类,你可以写的根源,处理所有底层复杂的东西确保修改是验证地、可转换地、有效地保存到.config文件中。要使ConfigurationElementCollection可修改,必须添加方法编辑集合。我们之前的ExampleThingElementCollection类添加一些方法使它可修改:


 
  1. #region Methods  
  2.         public void Add(ThingElement thing)  
  3.         {  
  4.             base.BaseAdd(thing);  
  5.         }  
  6.  
  7.         public void Remove(string name)  
  8.         {  
  9.             base.BaseRemove(name);  
  10.         }  
  11.  
  12.         public void Remove(ThingElement thing)  
  13.         {  
  14.             base.BaseRemove(GetElementKey(thing));  
  15.         }  
  16.  
  17.         public void Clear()  
  18.         {  
  19.             base.BaseClear();  
  20.         }  
  21.  
  22.         public void RemoveAt(int index)  
  23.         {  
  24.             base.BaseRemoveAt(index);  
  25.         }  
  26.  
  27.         public string GetKey(int index)  
  28.         {  
  29.             return (string)base.BaseGetKey(index);  
  30.         }  
  31.         #endregion 

一定要記住添加setters到配置元素集合包括的配置元素。添加一些公有的構造器對簡化創建和填充配置元素到集合非常有用。一旦你已經做了必要的修改允許你的配置設置能在運行時修改,你可以調用Configuration類的Save()方法。Save()方法有三種不同的重載,允許你控制究竟要保存什麽和強迫保存,即使沒有變化。

Configuration.Save() - 僅保存修改了的值
Configuration.Save(ConfigurationSaveMode) - 保存指定類別的修改,如果存在修改
Configuration.Save(ConfigurationSaveMode, bool) - 保存指定類別的修改,迫使進行保存,如果第二個參數為true
ConfigurationSaveMode枚舉具有以下值:

Full - 保存所有配置屬性,不管是否有所變化
Modified - 保存已修改的屬性,即使當前的值和原來是一樣的
Minimal - 保存已經修改且和原來值不一樣的屬性
Configuration對象也有一個SaveAs()方法,他有跟Save()方法一樣的基本重載。SaveAs()方法要求一個文件名作為第一個參數,表示要將配置文件保存到的路徑和文件名。

延伸阅读

    评论