在 C# 中创建自定义配置节






4.79/5 (29投票s)
创建类似于 AppSettings 的自定义配置节。它存储开发和生产环境的设置,并根据应用程序执行所在的机器配置返回适当的设置。
引言
本项目的目的是演示如何使用 Configuration Manager API 创建自定义配置节。我的示例基于许多公司在将应用程序从开发环境部署到生产环境时遇到的常见问题。很多时候,不同环境之间的配置设置是不同的。本项目实现的自定义配置节将存储开发和生产配置设置,并根据代码库设置返回相应的设置。
此演示将引导您创建程序集 (DLL),以实现读取自定义配置节所需的 Configuration Manager API 类。
建议下载并使用 Visual Studio 2005 打开示例应用程序。这样做可以节省时间,并有助于理解本演示中提到的不同方面。
本文内容概述
本文将解释如何创建自定义配置节。它解释了如何实现读取自定义配置节所需的 Configuration Manager API 基类。然后,它描述了如何创建一个包装类,该类模仿 AppSettings
类,并略微修改以根据“codebase”设置感知环境。本文将解释如何执行以下操作:
- 在应用程序配置文件中配置自定义配置节。
- 如何实现 Configuration Manager API 基类以读取自定义配置节。
- 实现
System.Configuration.ConfigurationElement
- 实现
System.Configuration.ConfigurationElementCollection
- 实现
System.Configuration.ConfigurationSection
- 创建模仿
System.Configuration.ConfigurationManager.AppSettings
的包装类 - 配置 Visual Studio 以便为配置文件中的自定义配置节提供智能感知和 XML 标签验证。
工作原理
需要在 Machine.Config 文件中创建一个名为 Codebase
的新 appSettings
设置。此设置告诉 SHI.WebTeam.Common.Configuration.ConfigurationSettings.AppSettings
类检索和存储应用程序正在执行的环境的设置。
SHI.WebTeam.Common.Configuration.ConfigurationSettings.AppSettings
类还会检索存储在配置文件默认 appSettings
节中的设置。shiSettings
节中的所有设置将覆盖 appSettings
节中的设置。appSettings
节的功能未被修改。无论 Codebase
值如何,配置文件 appSettings
节中的所有设置都是相同的。
SHI.WebTeam.Common.Configuration
包装类有一个名为 AppSettings
的静态属性,它返回一个模仿 Microsoft 的 System.Configuration.ConfigurationManager.AppSettings
实现的 NameValueCollection
。
实现 System.Configuration.ConfigurationElement
下面列出的代码实现了 System.Configuration.ConfigurationElement
。它代表配置文件中的一个元素。
配置文件中的元素指的是基本的 XML 元素或节。基本元素是一个带有相关属性的简单 XML 标签。节与基本元素相对应。复杂节可以包含一个或多个基本元素、一个元素集合和其他节。
此类表示存储在配置文件 shiSettings
节中的 XML 数据。基本上,它在类和 XML 之间创建映射。ConfugationManager
处理 XML,而不是直接处理 XML。如果在配置文件 shiSettings
“Add
”元素中添加新属性,也必须在此类中定义。
/*********************************************************************
* Description : This class maps the attributes elements in the
* configuration file to this class. Represents the
* <add /> element.
**********************************************************************/
using System;
namespace SHI.WebTeam.Common.ConfigurationManager
{
/// <summary>
/// This class represents the structure of the SHI settings structure
/// in the WebConfig.Conf or App.Conf. These are the attributes.
/// </summary>
public class ShiSettingElements: System.Configuration.ConfigurationElement
{
/// <summary>
/// Returns the key value.
/// </summary>
[System.Configuration.ConfigurationProperty("key", IsRequired = true)]
public string Key
{
get
{
return this["key"] as string;
}
}
/// <summary>
/// Returns the setting value for the production environment.
/// </summary>
[System.Configuration.ConfigurationProperty("prod", IsRequired = true)]
public string Prod
{
get
{
return this["prod"] as string;
}
}
/// <summary>
/// Returns the setting value for the development environment.
/// </summary>
[System.Configuration.ConfigurationProperty("dev", IsRequired = true)]
public string Dev
{
get
{
return this["dev"] as string;
}
}
/// <summary>
/// Returns the setting description.
/// </summary>
[System.Configuration.ConfigurationProperty("desc",IsRequired = false)]
public string Desc
{
get
{
return this["desc"] as string;
}
}
}
}
实现 System.Configuration.ConfigurationElementCollection
ConfigurationElementCollection
表示配置文件中的元素集合。此类是存储在配置文件中的所有 shiSettings
的集合。
/*********************************************************************
* Description : This class is the collection of settings loaded
* from the WebConfig.Conf or App.Conf.
**********************************************************************/
using System;
namespace SHI.WebTeam.Common.ConfigurationManager
{
public class ShiSettingCollection :
System.Configuration.ConfigurationElementCollection
{
public ShiSettingElements this[int index]
{
get
{
return base.BaseGet(index) as ShiSettingElements;
}
set
{
if (base.BaseGet(index) != null)
{
base.BaseRemoveAt(index);
}
this.BaseAdd(index, value);
}
}
protected
override System.Configuration.ConfigurationElement CreateNewElement()
{
return new ShiSettingElements();
}
protected override object GetElementKey(
System.Configuration.ConfigurationElement element)
{
return ((ShiSettingElements)element).Key;
}
}
}
实现 System.Configuration.ConfigurationSection
ConfigurationSection
类实现了自定义节类型。ConfigurationSection
类提供自定义处理和对自定义配置节的程序化访问。此类从配置文件中“shiConfiguration
”节检索 shiSettings
。
using System;
using System.Web.Configuration;
namespace SHI.WebTeam.Common.ConfigurationManager
{
/// <summary>
/// This class is actually what loads the custom settings.
/// </summary>
public class ShiConfiguration : System.Configuration.ConfigurationSection
{
private static string sConfigurationSectionConst = "shiConfiguration";
/// <summary>
/// Returns an shiConfiguration instance
/// </summary>
public static ShiConfiguration GetConfig()
{
return (ShiConfiguration)System.Configuration.ConfigurationManager.
GetSection(ShiConfiguration.sConfigurationSectionConst) ??
new ShiConfiguration();
}
[System.Configuration.ConfigurationProperty("shiSettings")]
public ShiSettingCollection shiSettings
{
get
{
return (ShiSettingCollection)this["shiSettings"] ??
new ShiSettingCollection();
}
}
}
}
创建包装类
此类使用上面创建的类,根据当前 Codebase
值,将设置从配置文件加载到静态 NameValueCollection
中。代码已添加注释,以解释正在发生的事情。请注意“AppSettings
”属性;它使用 Singleton 技术返回一个静态索引器。还有一个名为 ShiSettingsSection
的私有子类,它根据代码库将 shiSettings
和 AppSettings
节加载到 NameValueCollection
中。
/*********************************************************************
* Description : This class is the wrapper which loads the settings
* stored in the shiSettings section in the
* configuration file. (Web.Config or App.Config)
* Settings returned by this class are based on the
* value of the Codebase setting in the machine.conf
* file. The AppSettings property has been designed
* to mimic Microsoft's AppSettings.
**********************************************************************/
using System;
using SHI.WebTeam.Common.Configuration.Enum;
using System.Collections.Specialized;
using System.Collections;
namespace SHI.WebTeam.Common.Configuration.Enum
{
public enum CodeBases { Development, Production, Invalid, NotSet };
}
namespace SHI.WebTeam.Common.Configuration
{
public class ConfigurationSettings
{
private static object sLockingObject = new object();
private static CodeBases sCodebase = CodeBases.NotSet;
private static ShiSettingsSection sSettings = null;
/// <summary>
/// Gets the SHI.Configuration.AppSettingsSection data based on the
/// machine's codebase for the current application's
/// codebase default settings.
/// In addition gets the System.Configuration.AppSettingSection data for
/// the current application's default settings if the setting does not
/// exist in the SHI.Configuration.AppSettingsSection.
/// </summary>
/// <param name="name">The name of the setting to be retreived.</param>
/// <returns>Returns the setting specified.</returns>
[System.Diagnostics.DebuggerNonUserCode()]
public static NameValueCollection AppSettings
{
lock (sLockingObject)
{
//If the settings weren't loaded then load them.
if (sSettings == null)
{
sSettings = new ShiSettingsSection();
sSettings.GetSettings();
}
}
return (NameValueCollection)sSettings;
}
/// <summary>
/// Gets the Codebase setting in which the application is
/// being executed.
/// </summary>
static public CodeBases CodeBase
{
get
{
if (ConfigurationSettings.sCodebase == CodeBases.NotSet)
{
//Get the codebase value from the config file.
string ConfigCodeBase =
System.Configuration.ConfigurationManager.
AppSettings["Codebase"].ToLower();
//Convert the codebase string to the enum value.
if (ConfigCodeBase == "prod")
ConfigurationSettings.sCodebase = CodeBases.Production;
else if (ConfigCodeBase == "dev")
ConfigurationSettings.sCodebase = CodeBases.Development;
else
ConfigurationSettings.sCodebase = CodeBases.Invalid;
}
return ConfigurationSettings.sCodebase;
}
}
/// <summary>
/// Validates the value of the codebase setting. If the value is not
/// supported an exception is thrown.
///
/// The codebase settings should be set in the machine.config file
/// usually located at
/// \WINDOWS\Microsoft.NET\Framework\v2.X.X\Config\Machine.Config.
///
/// In the appSettings section create a key called
/// "codebase" and a value of
/// "Prod" or "Dev". Missing values or other values will be concidered
/// invalid.
/// <returns>Returns the value of the codebase
///setting machine.config file.</returns>
[System.Diagnostics.DebuggerNonUserCode()]
static private CodeBases validateCodebase()
{
if (ConfigurationSettings.CodeBase == CodeBases.NotSet)
{ //The codebase setting is not configured throw an exception.
throw new Exception(
"Missing codebase value in the machine.config " +
"file under the appSettings. Allowed values are \"
prod\" and \"dev\"");
}
else if (ConfigurationSettings.CodeBase == CodeBases.Invalid)
{ //The codebase isn't the expected value throw an exception.
throw new Exception(
"Invalid codebase value in the machine.config file " +
"under the appSettings. Allowed values are \"
prod\" and \"dev\"");
}
//The codebase was set and value, so return the
//current machine codebase.
return ConfigurationSettings.CodeBase;
}
#region Private shiSettingsSection Class
private class ShiSettingsSection : NameValueCollection
{
/// <summary>
/// Populates the collection with the SHI and Application Settings
/// based on the current codebase.
/// </summary>
[System.Diagnostics.DebuggerNonUserCode()]
public void GetSettings()
{
//If the settings collection is not populated, populate it.
if (base.Count == 0)
{
//Validate the codebase and get the current Codebase.
CodeBases codebase = validateCodebase();
//Load the ShiConfiguration section from the .Config file.
SHI.WebTeam.Common.ConfigurationManager.ShiConfiguration
ConfigSettings =
SHI.WebTeam.Common.ConfigurationManager.
ShiConfiguration.GetConfig();
//Only populate if the section exists.
if (ConfigSettings != null)
{
//Add the setting for the current machine's codebase to the
//settings collection. Current Codebases
//values are "Production"
//and "Development". The validateCodebase method inforces
//this.
for (int i = 0; i < ConfigSettings.shiSettings.Count; i++)
{
if (ConfigurationSettings.CodeBase ==
CodeBases.Production)
{
base.Add(ConfigSettings.shiSettings[i].Key,
ConfigSettings.shiSettings[i].Prod);
}
else if (ConfigurationSettings.CodeBase ==
CodeBases.Development)
{
base.Add(ConfigSettings.shiSettings[i].Key,
ConfigSettings.shiSettings[i].Dev);
}
else
{
throw new Exception(
"The configured codebase value is " +
"not currently implemented.");
}
}
}
// Load System.ConfigurationManager.AppSettings for
//all settings
// not loaded in the SHI Configuration Setting Section.
NameValueCollection appSettings =
System.Configuration.ConfigurationManager.AppSettings;
for (int i = 0; i < appSettings.Count; i++)
{
string key = appSettings.Keys[i];
//If the Key does not exist in the SHI settings add it.
if (base[key] == null)
{
base.Add(key, appSettings[i]);
}
}
}
}
#region Overrides
/// <summary>
/// This configuration is read only and calling
/// this method will throw an exception.
/// </summary>
[System.Diagnostics.DebuggerNonUserCode()]
public override void Clear()
{
throw new Exception("The configuration is read only.");
}
/// <summary>
/// This configuration is read only and calling this
/// method will throw an exception.
/// </summary>
[System.Diagnostics.DebuggerNonUserCode()]
public override void Add(string name, string value)
{
throw new Exception("The configuration is read only.");
}
/// <summary>
/// This configuration is read only and calling this method
/// will throw an exception.
/// </summary>
[System.Diagnostics.DebuggerNonUserCode()]
public override void Remove(string name)
{
throw new Exception("The configuration is read only.");
}
/// <summary>
/// This configuration is read only and calling this
/// method will throw an exception.
/// </summary>
[System.Diagnostics.DebuggerNonUserCode()]
public override void Set(string name, string value)
{
throw new Exception("The configuration is read only.");
}
#endregion
}
#endregion
}
}
为自定义配置节配置配置文件
为了让 .NET Framework 理解新的配置节,需要将 <configSections>
元素添加到 Web.Config、App.Config 或 Machine.Config 文件中。由于包含的示例应用程序是 ASP.NET 应用程序,我们将这些设置添加到 web.config 文件中。将以下 XML 添加到应用程序配置文件中的 <configuration>...</configuration>
元素内。
<!-- This tells the Configuration Manager
API about the section handler implementation. -->
<section name="shiConfiguration"
type="SHI.WebTeam.Common.ConfigurationManager.ShiConfiguration,
ShiConfigurationSectionHandler,
Version=1.0.0.0,
Culture=neutral"
restartOnExternalChanges="false"
requirePermission="false"
/>
<!-- Place all environment specific setting in this section. -->
<shiConfiguration>
<shiSettings>
<add key="SettingName"
prod="Production Setting"
dev="Development Setting"
desc="Some description, but not required."
/>
<add key="testing"
prod="Hello production world!"
dev="Hello development world!"
/>
</shiSettings>
</shiConfiguration>
配置文件中的 XML 标签智能感知和验证
Visual Studio 2005 需要配置如何解释配置文件中的新配置节。完成此操作后,智能感知和标签验证将开始对新的配置节生效。需要在 DotNetConfig.xsd 文件中添加一个新的架构节。
编辑 DotNetConfig.xsd,通常位于 C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas\DotNetConfig.xsd 文件夹中。如果找不到该文件,请在系统上的所有驱动器上进行搜索。我建议在修改文件之前备份一份副本。找到文件后,在 Notepad.exe 中打开它并添加以下 XML 片段
<xs:element name="shiConfiguration" vs:help="configuration/shiConfiguration">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="shiSettings"
vs:help="configuration/shiConfiguration/shiSettings">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="add"
vs:help="configuration/shiConfiguration/shiSettings/add">
<xs:complexType>
<xs:attribute name="key" type="xs:string"
use="required" />
<xs:attribute name="prod"
type="xs:string" use="required" />
<xs:attribute name="dev"
type="xs:string" use="required" />
<xs:attribute name="desc"
type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="remove"
vs:help="configuration/shiConfiguration/shiSettings/remove">
<xs:complexType>
<xs:attribute name="key" type="xs:string"
use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="clear"
vs:help="configuration/shiConfiguration/shiSettings/clear">
<xs:complexType>
<!--tag is empty-->
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
重要的旁注
- 如果此程序集在 Web 服务器上使用,我建议将其安装到 GAC(全局程序集缓存)中。我还建议将
<configSections>
放入 machine.confg 文件中。这样,它对整个服务器都是全局的。 - 不要将
CodeBase
设置放入 App.Config 或 Web.Config 文件中。将其放入 Machine.Config。避免将环境特定设置放入错误的环境中,这不就是全部想法吗? - 必须将配置节添加到配置文件中。
关注点
- 在 C# 中,无法创建静态索引器。解决方法非常简单,并且可以完成相同的任务。它被称为 单例模式。查看链接获取更多详细信息。这是一个很酷的技巧。
Using the Code
要从自定义配置节中检索设置,只需执行以下操作。
<!-- Put this code into the web.config or app.config file. -->
<shiConfiguration>
<shiSettings>
<add key="SettingName" prod="Production Setting"
dev="Development Setting"
desc="Some description, but not required."/>
<add key="testing" prod="Hello production world!"
dev="Hello development world!"/>
</shiSettings>
</shiConfiguration>
下面是一个名为“Something
”的公共类的示例。请注意,当使用 SHI 实现获取设置时,它与 Microsoft 的 AppSettings
的工作方式类似。只需将 using
指令从 System.Configuration
更改为 SHI.WebTeam.Common.Configuration
,即可使代码感知环境。
using SHI.WebTeam.Common.Configuration;
public class Something
{
public Somthing()
{
//Gets the setting from the SHI Custom Configuration
//Section, NOT Microsoft's
string Testing = ConfigurationSettings.AppSettings["testing"];
string SettingName = ConfigurationSettings.AppSettings["SettingName"];
//Remember the SHI implementation also loads the setting from the
//AppSettings section
string AnAppSettingsSetting =
ConfigurationSettings.AppSettings["appSettings"];
...
}
}
结论
最后,我想说这是我第一次向网站发布任何内容。所以我希望我做得很好,并且解释得足够透彻。我希望您喜欢这个示例并发现它有用。如果有任何问题或意见,请随时与我联系。