65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 XML 序列化实现强类型自定义配置节

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (5投票s)

2007年12月29日

CPOL

3分钟阅读

viewsIcon

64903

downloadIcon

758

本文演示了一种简单的方法,可以获得强类型配置对象以在代码中使用 XML 序列化

引言

本文介绍了一种在配置文件中使用 XML 序列化来实现强类型配置项的简单机制。

背景

本文使用以下概念(读者应具备基本了解):

  1. 泛型类
  2. XML 序列化
  3. 处理配置文件

Using the Code

注意:代码以两个独立的解决方案文件形式提供下载。一个使用 IConfigurationSectionHandler 接口(在 .NET v2.0 及以上版本中已弃用),另一个则使用 ConfigurationSection 类来实现相同功能。两个项目都包含两个类库:

  1. Citrus.Configuration - 类库
  2. Citrus.Configuration.Demo - 演示应用程序

强类型配置实体在代码清晰度、可读性、编程便捷性等方面具有很大优势。假设我们需要在配置文件中保存电子邮件服务器的名称和 IP 地址。我们需要能够将这些详细信息作为强类型实体从配置文件中检索出来。也就是说,我们可以有一个 EmailServerSettings 对象,它有两个属性 NameIP,可以从中访问。

这只是一个示例,该方法可以轻松地重用和扩展到您选择的任何可配置实体。

首先,需要定义 EmailServerSettings 类来表示我们的强类型实体。

/// <summary>
/// This is a sample class that is used
/// to describe XML serialization based configuration
/// section usage
/// </summary>
[XmlRoot("EmailServerSettings")]
public class EmailServerSettings
{
    [XmlElement("IP")]
    // note the use of implicit property accessors in C# 3.0
    public string IP { get; set; }

    [XmlElement("Name")]
    public string Name { get; set; }

    #region Overrides
    public override string ToString()
    {
        return String.Format("{0} email server ({1})", Name, IP);
    }
    #endregion
}

这非常简单。为了实现 XML 序列化,我们需要用必要的 XML 属性标记属性和类。

.NET 1.1 方法

接下来,我们定义一个基于泛型 XML 序列化的配置节处理器。此类实现了 IConfigurationSectionHandler 接口。此接口在 .NET 2.0 及更高版本中已被弃用。有关在 .NET 2.0 中实现相同功能的说明,请参阅“.NET 2.0 方法”部分。

/// <summary>
/// Handles the access to a generic configuration section using
/// XML serialization
/// </summary>
/// <typeparam name="T">The type of the configuration section</typeparam>
public class XmlSectionHandler<T> : IConfigurationSectionHandler
{
    #region Properties and fields

    private XmlSerializer serializer = new XmlSerializer(typeof(T));
    public XmlSerializer Serializer { get; set; }

    #endregion

    #region IConfigurationSectionHandler Members

    public virtual object Create(object parent, object configContext, XmlNode section)
    {
        return serializer.Deserialize(new StringReader(section.OuterXml));
    }

    #endregion
}

XmlSectionHandler 是一个泛型类;它使用关联的类型来创建执行核心 XML 反序列化的序列化器。

此时,我们已经具备了基本组成部分;还编写了一个简单的辅助类,用于提供强类型配置实体。

/// <summary>
/// Configuration helper class that exposes generic
/// section retrieval functionality
/// </summary>
public static class ConfigurationHelper
{
    /// <summary>
    /// Retrieves a typed configuration section for
    /// the current application's default configuration
    /// </summary>
    /// <typeparam name="T">
    /// The type to bind to the configuration section</typeparam>
    /// <param name="sectionName">
    /// The name of the configuration section</param>
    /// <returns></returns>
    public static T GetSection<T>(string sectionName)
    {
        return (T)ConfigurationManager.GetSection(sectionName);
    }

    /// <summary>
    /// Retrieves a typed configuration section for
    /// the current application's default configuration
    /// </summary>
    /// <typeparam name="T">
    /// The type to bind to the configuration section</typeparam>
    /// <returns></returns>
    public static T GetSection<T>()
    {
        return (T)ConfigurationManager.GetSection(typeof(T).Name);
    }
}

该辅助类仅提供一些有用的例程,用于将配置对象强制转换为指定类型。仅此而已。这三个类构成了 Citrus.Configuration 类库的核心类。

要使用它们,首先需要更新配置文件。以下是一个使用 EmailServerSettingsXmlSectionHandler 的自定义配置节的简单配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <!-- The following is used to describe our custom section -->
    <section name="EmailServerSettings"
type="Citrus.Configuration.XmlSectionHandler`1
      [[Citrus.Configuration.EmailServerSettings,
      Citrus.Configuration,
      Version=1.0.0.0,
      Culture=neutral,
      PublicKeyToken=null]],
      Citrus.Configuration,
      Version=1.0.0.0, Culture=neutral,
      PublicKeyToken=null" />
  </configSections>
  <!-- Now that our section has been declared, use it -->
  <EmailServerSettings configSource="EmailServerSettings.config" />
</configuration>

外部 EmailServerSettings.config 文件本质上是该类的 XML 序列化版本。

<!-- A simple XML file containing settings for a email server -->
<EmailServerSettings>
  <Name>Coldmail</Name>
  <IP>127.0.0.1</IP>
</EmailServerSettings>

现在,我们准备在代码中实际使用所有这些功能。

// The following will give us the email server settings
EmailServerSettings emailServerSettings1 =
	ConfigurationHelper.GetSection<emailserversettings>("EmailServerSettings");
EmailServerSettings emailServerSettings2 = 
	ConfigurationHelper.GetSection<emailserversettings>();

// Print the information out
Console.WriteLine(emailServerSettings1);
Console.WriteLine(emailServerSettings2);

实际上,您可以轻松地使用 emailServerSettings1.NameemailServerSettings1.IP,从而获得强类型配置实体。

要根据您的需求扩展此功能,您需要定义自己的特定配置类(如 EmailServerSettings 类),并在您的 config 文件中添加适当的配置节。

.NET 2.0 方法

由于在此版本中 IConfigurationSectionHandler 已被弃用,我们必须将 XmlSectionHandler 类重新定义为从 ConfigurationSection 派生的类。

public class XmlSection<T> : ConfigurationSection where T: class

(注意 .NET 2.0 版本中的类名已更改)。为了在这种情况下处理 XML 序列化,必须进行细微修改。这些修改包括重写 ConfigurationSectionInit()DeserializeSection() 方法。此外,XmlSection 实现了一些基本支持,可以将修改后的配置详细信息保存回配置文件。要使用 XmlSection 类,请参阅下面的代码片段:

// The object that represents our email server's settings
EmailServerSettings anEmailServer;
// Get the section that is specified an external configuration file
anEmailServer = XmlSection<EmailServerSettings>.GetSection("EmailSettings");
Console.WriteLine(anEmailServer);

// Update the section, refresh and load it again
Config.Configuration c = Config.ConfigurationManager.OpenExeConfiguration
			(Config.ConfigurationUserLevel.None);
XmlSection<EmailServerSettings>.GetSection("EmailSettings", c).Name = "Hello";
c.Save();
Config.ConfigurationManager.RefreshSection("EmailSettings");
anEmailServer = XmlSection<EmailServerSettings>.GetSection("EmailSettings");
Console.WriteLine(anEmailServer);

// Get settings that are specified inline
anEmailServer = XmlSection<EmailServerSettings>.GetSection("ProxyEmailServer");
Console.WriteLine(anEmailServer);

相应的 config 文件如下:

<configuration>
    <configSections>
        <section name="EmailSettings"
type="Citrus.Configuration.XmlSection`1
[[Citrus.Configuration.EmailServerSettings, Citrus.Configuration]],
Citrus.Configuration"/>
        <section name="ProxyEmailServer"
type="Citrus.Configuration.XmlSection`1
[[Citrus.Configuration.EmailServerSettings, Citrus.Configuration]],
Citrus.Configuration"/>
    </configSections>
    <EmailSettings configSource="EmailSettings.config" />
    <ProxyEmailServer>
        <Name>Proxy</Name>
        <IP>127.0.0.1</IP>
    </ProxyEmailServer>
</configuration>

如果以上内容对您有任何帮助,请告诉我。祝您使用愉快。

历史

[ .] 初始版本
[+] 新版本。使用 ConfigurationSection 类的 .NET 2.0 特定实现
[+] 2008 年 1 月 7 日 (v1.1)
在之前的版本中,XmlSerializer 是使用 XmlSerializer(Type, XmlRootAttribute) 构造函数即时创建的。根据设计,使用此构造函数 效率不高。因此,实现了一个简单的 SerializerCache 来缓存 XmlSerializer 对象,以便它们可以被重用,从而使使用更快、更高效。另一个小的改动是将 EmailServerSettings 类移到了 Citrus.Configuration 库之外。

© . All rights reserved.