在 app.config 和 web.config 中使用 XAML






4.36/5 (9投票s)
继续使用 XAML 配置应用程序
引言
因此,当我们上次中断时,我们一直在讨论使用 XAML 作为存储应用程序配置信息的手段。在讨论过程中,我们说明了如何通过 XamlReader
类将包含强类型配置数据的 XAML 文件加载到进程中,并在运行时将其用作预定义类型的对象,以维护脱机配置数据。我们进一步通过创建一个通用类并为其提供一些 public
属性(以表示可配置项)来说明这一点,然后创建了一个定义该通用类实例的 XAML 文件。此 XAML 文件随后被读取并用于配置应用程序。
这对于特定类型的应用程序来说是一个很棒的工具,而且效果非常好。我们对这种方法没有遇到任何问题,并将其用作我们在上一篇文章中说明的应用程序 LaunchPoint 的基础配置机制。但是,正如我们之前提到的,.NET 本身已附带一套通常一直存在的配置文件。这些是 app.config 和 web.config 文件(在本文中统称为 *.config)。这些配置文件已深入集成到基于 .NET Framework 的各种技术(如 ASP.NET 和 WPF)的实现中,因此无法轻易替换。对于这些类型的场景,采用同时利用这两种模式的方法将是理想的选择。这样,我们就可以使用下一代配置方法,而不会丢失已存在的旧版 *.config 文件。当然,我们可以通过在现有配置中添加一个新的配置文件来实现这一点,该文件在 *.config 系统之外运行,而且这没什么问题。事实上,当配置需要运行时更新并必须持久化回文件系统时,这种拆分方法实际上优于静态 *.config 样式。然而,为了实现统一,我们认为有必要引入自定义配置节的使用,以更无缝地合并这两种方法。
实现方法
要使用示例或跟随讨论,您可能需要获取 MindFactorial.Library
开源项目(可以在 此处找到),以构建并获取 mindfactorial.library.dll 文件。如果您不想查看源代码,该项目也包含了此文件的副本。如果您需要创建自己的实现,我们还包含了 XamlConfigSectionHandler
实现的代码。
所以,总而言之,我们可以采用如下所示的 Person
配置定义
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
public ContactInfo Contact { get; set; }
}
public class ContactInfo
{
public Address StreetAddress { get; set; }
public string EmailAddress { get; set; }
public string HomePhoneNumber { get; set; }
public string CellPhoneNumber { get; set; }
public string FaxNumberNumber { get; set; }
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
出于任何原因,将其表示为 XAML:
<Person xmlns="clr-namespace:XamlConfig;assembly=XamlConfig"
FirstName="John"
LastName="Smith"
>
<Person.Contact>
<ContactInfo CellPhoneNumber="123456789"
FaxNumberNumber="123456789"
HomePhoneNumber="123456789"
EmailAddress="test@test.com">
<ContactInfo.StreetAddress>
<Address>
<Address.Street>1234 fifth street</Address.Street>
<Address.City>sammamish</Address.City>
<Address.State>wa</Address.State>
<Address.Zip>98074</Address.Zip>
</Address>
</ContactInfo.StreetAddress>
</ContactInfo>
</Person.Contact>
</Person>
到目前为止,我们都应该知道这一点。如果不知道,请阅读 上一篇文章。
碰巧的是,通过利用自定义配置处理程序/配置节模式,可以将这个确切的 XAML 添加到您现有的 *.config 文件中。提供的示例利用了 (mind)! 配置处理程序。示例中 XamlConfigSectionHandler
的实现非常简单,如果您想创建功能更多的自定义实现。
public class XamlConfigSectionHandler :
System.Configuration.IConfigurationSectionHandler
{
object _XAML_instance = null;
public T GetInstance<T>()
{
return (T)_XAML_instance;
}
public object Create(object parent, object configContext, System.Xml.XmlNode section)
{
StringReader XAML = new StringReader(section.OuterXml);
XmlReader XAML_reader = XmlReader.Create(XAML);
_XAML_instance = System.Windows.Markup.XamlReader.Load(XAML_reader);
return this;
}
}
因此,从示例中可以看出,这个处理程序所做的只是获取自定义节中的 XAML 并将其作为 XAML 加载。此外,还存在一个通用方法 GetInstance
,它只是将 XAML 创建的实例强制转换为调用者指定的类型参数。可以假定调用者知道 XAML 对象的类型,因为该类型必须在运行时可供 XamlReader
类访问。最终的配置文件将如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="Person" type="MindFactorial.Library.XamlConfigSectionHandler,
MindFactorial.Library" />
</configSections>
<Person xmlns="clr-namespace:XamlConfig;assembly=XamlConfig"
FirstName="John"
LastName="Smith"
>
<Person.Contact>
<ContactInfo CellPhoneNumber="123456789"
FaxNumberNumber="123456789"
HomePhoneNumber="123456789"
EmailAddress="test@test.com">
<ContactInfo.StreetAddress>
<Address>
<Address.Street>1234 fifth street</Address.Street>
<Address.City>sammamish</Address.City>
<Address.State>wa</Address.State>
<Address.Zip>98074</Address.Zip>
</Address>
</ContactInfo.StreetAddress>
</ContactInfo>
</Person.Contact>
</Person>
</configuration>
同样,我们这里使用的是 MindFactorial
版本的配置节处理程序,但您可以自由选择使用它还是创建具有更多或更少功能的自己的 XAML 节处理程序。我们的方法是尽可能保持通用,以便使用相同的节处理程序支持多种形式的 XAML。因此,下面的 app.config 文件也是有效的:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="Person" type="MindFactorial.Library.XamlConfigSectionHandler,
MindFactorial.Library" />
<section name="String" type="MindFactorial.Library.XamlConfigSectionHandler,
MindFactorial.Library" />
</configSections>
<Person xmlns="clr-namespace:XamlConfig;assembly=XamlConfig"
FirstName="John"
LastName="Smith"
>
<Person.Contact>
<ContactInfo CellPhoneNumber="123456789"
FaxNumberNumber="123456789"
HomePhoneNumber="123456789"
EmailAddress="test@test.com">
<ContactInfo.StreetAddress>
<Address>
<Address.Street>1234 fifth street</Address.Street>
<Address.City>sammamish</Address.City>
<Address.State>wa</Address.State>
<Address.Zip>98074</Address.Zip>
</Address>
</ContactInfo.StreetAddress>
</ContactInfo>
</Person.Contact>
</Person>
<String xmlns="clr-namespace:System;assembly=mscorlib" >
another custom config section using XAML
</String>
</configuration>
在 app.config 文件的第二次迭代中,我们说明了在同一个 *.config 文件中使用多个 XAML 实例而无需更改节处理程序。下面的代码是读取 *.config 文件中 XAML 节的完整源代码列表。之前的实现使用了独立的 XAML 配置文件,并包含在内以说明两者之间的相似性。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Markup;
using System.IO;
using MindFactorial.Library;
using System.Configuration;
namespace XamlConfig
{
class Program
{
static void Main(string[] args)
{
//XAML in custom configuration file
Person XAML_person1 = null, XAML_person2 = null;
using (FileStream XAML_stream = File.OpenRead("../../person.XAML"))
{
XAML_person1 = (Person)System.Windows.Markup.XamlReader.Load(XAML_stream);
Console.WriteLine(XAML_person1);
}
//person XAML in app.config
XamlConfigSectionHandler XAML_person_section =
(XamlConfigSectionHandler)ConfigurationManager.GetSection("Person");
XAML_person2 = XAML_person_section.GetInstance<Person>();
//string XAML in app.config
XamlConfigSectionHandler XAML_string_section =
(XamlConfigSectionHandler)ConfigurationManager.GetSection("String");
string data = XAML_string_section.GetInstance<string>();
}
}
}
希望到此为止,您应该已经认识到 XAML 的价值,并开始理解为什么它是配置应用程序的明智选择。无论是集成到现有的配置文件中还是作为独立文件存在,XAML 都是一种强大、灵活且极其可扩展的替代简单 XML 的配置信息表达方式。
历史
- 2008年4月16日:初稿