使用 Unity(二):配置 Unity 、读取配置信息和获取对象
使用 Unity(二):配置 Unity 、读取配置信息和获取对象
和 Enterprise Library 的其他应用程序块一样,Unity 的行为也可以通过配置来指定。
Unity 应用程序块可以从 XML 配置文件中读取配置信息。配置文件可以是 Windows Forms 应用程序的 App.config 或者 ASP.NET 应用程序的 Web.config。当然,也可以从任何其他 XML 格式的文件或者其他数据源中加载配置信息。
在本文中,将和大家一起来学习 Unity 配置文件的格式、配置的读取、通过示例说明实例的获取。
1. Unity 配置文件的格式
Unity 配置文件看起来像下面这样:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity>
<containers >
<container name="containerOne" >
<types>
<type type="System.Data.IDbConnection,System.Data"
mapTo="DorianDeng.UnityConfigurationExe.MyDefaultConnection,DorianDeng.UnityConfigurationExe" />
<type name="baseMap" type="System.Data.Common.DbConnection,System.Data"
mapTo="DorianDeng.UnityConfigurationExe.MyDbConnection,DorianDeng.UnityConfigurationExe" lifetime="Transient" />
<type name="interfaceSingleton" type="System.Data.IDbConnection,System.Data"
mapTo="DorianDeng.UnityConfigurationExe.MyDbConnection,DorianDeng.UnityConfigurationExe" lifetime="Singleton"/>
</types>
<instances>
<add name="MyInstance1" type="System.String" value="Some value" />
<add name="MyInstance2" type="System.DateTime" value="2008-02-05T17:50:00" />
</instances>
<extensions>
<!--<add type="MyApp.MyExtensions.SpecialOne" />-->
</extensions>
</container>
</containers>
</unity>
</configuration>
1.1 配置节
Unity 的配置节的名称为”unity",节处理程序的类型为 Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,它包含在程序集 Microsoft.Practices.Unity.Configuration 中。
1.2 unity 的子元素
unity 的子元素包含了一个 containers 元素,此元素有一个必须的属性 Default (此属性在目前的版本中不可用),它用于指定在不指定容器获取容器的配置时的默认容器。
containers 元素可以包含若干个 container 元素。container 元素就是每个容器的配置,它有一个可选的 name 属性,用于指定容器的名称。
container 元素有下列子元素:
types 元素
instances 元素
extensions 元素
注意:不能嵌套定义容器,即 container 元素不能嵌套。
1.3 types 元素
types 元素是 container 元素的子元素之一。包含任意数量的 type元素,用以添加类型注册。
下面的表格列出了用于 types 的 type元素的属性。
属性 描述
name 在注册此类型时使用的名称。此属性是可选的,如果不指定此属性,所在的 add 元素即为默认的类型映射。
type 容器中配置的源类型。如果这是映射注册,这就是映射的起始对象的类型;如果这是单件注册,这就是对象的类型。此属性是必须的。
mapTo 类型映射的目标类型。如果这是映射注册,这就是映射的目标对象的类型。此属性是可选的。
lifetime 设置用于给定的类型和名称的生命周期。是一个来自 LifetimeStyle 枚举的值。有效的值是 Transient(默认),它导致了容器每次都创建一个新的实例;以及 Singleton,它使容器为每个请求返回同一实例。如果在配置一个单件时同时指定了 type 和 mapto 属性,SetSingleton 方法将返回指定在 mapTo 属性中的类型。如果 mapTo 属性没有指定值,SetSingleton 方法将返回指定在 type 属性中的类型。
在此的单件(Singleton)即是人们常说的单件模式中的单件。SetSingleton 方法是容器提供的用于获取单件的方法。容器会根据 lifetime 属性来决定生成实例的方式。
1.4 instances 子元素
instances 元素保持了用于此容器的已有对象实例的列表。这些对象(包括简单类型如数据库连接字符串)被用容器的 RegisterInstance 方法进行注册。instances 元素包含了一系列添加单个实例的 add 元素。
下面的表格列出了用于用于实例的 add 元素的属性。
属性 描述
name 注册此实例时使用的名称。此属性是可选的。
type 此实例的类型。此属性是可选的。如果忽略,假定的类型是 System.String。
value 用于初始化实例的值。此属性是必须的。
typeConverter 用以转换提供的值到实例的匹配类型的类型转换器。如果没有指定,将使用指定类型的默认转换器。此属性是可选的。
1.5 extensions 元素
extensions 元素保持了添加注册到 Unity 容器的扩展的列表。extensions 包含一系列添加单个扩展的 add 元素。
下面的表格列出了用于用于扩展的 add 元素的属性。
属性 描述
type 添加到容器的扩展的类型。此属性是必须的。
2 示例
我们现在仅对 types 子元素和 instances 子元素进行学习,extensions 子元素在随后单独进行。
在示例中,我们分别定义了二个继承自 System.Data.Common.DbConnection 类的 MyDefaultConnection 和 MyDbConnection,虽然这二个类并不能实现真正的连接,但在此做为示例已足够了。
2.1 读取配置创建容器
如文章开头配置文件中,我们定义了一个命名的窗口 "containerOne",因此,我们可以用下列代码来读取配置并用配置来初始化容器。
注意:Unity 应用程序块不会自动的读取配置信息,或者创建和准备容器。
/// <summary>
/// 创建容器。
/// </summary>
/// <returns></returns>
private static IUnityContainer CreateContainer() {
IUnityContainer container = new UnityContainer();
UnityConfigurationSection section
= (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers["containerOne"].GetConfigCommand().Configure(container);
return container;
}
在上面的代码中,我们用第一行来实例化一个容器,第二行使用 .NET 的 ConfigurationManager 类来读取配置节,第三行初始化容器。
如果我们定义了一个默认的容器(未命名的容器),那么,我们就可以用下列的代码来初始化容器:
section.Containers.Default.GetConfigCommand().Configure(container);
嵌套的容器为管理依赖注入和对象生命周期提供了有用的功能,这在以后的文章中会详细讨论。
虽然,在配置文件中我们并不能嵌套的定义容器,但可以使用代码来创建并初始化容器,如下面的代码所示:
IUnityContainer parentContainer = new UnityContainer();
IUnityContainer childContainer = parentContainer.CreateChildContainer();
UnityConfigurationSection section
= (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers["containerOne"].GetConfigCommand().Configure(parentContainer);
section.Containers["nestedChildContainer"].GetConfigCommand().Configure(childContainer);
2.2 创建默认实例
默认实例就是通过未命名的类型映射来注册的实例,如示例配置文件中的第一个 type。那么,我们就可以使用如下代码来获取并使用实例。(完整的代码请参见源文件。)
private static void DefaultMap() {
IUnityContainer container = CreateContainer();
IDbConnection connection = container.Get<IDbConnection>();
connection.Open();
connection.Close();
}
执行的效果如下图如示:
2.3 根据键和类型来获取对象
对于配置文件中的第二个 type 元素,我们可以用以下语句来获取对象:
DbConnection connection = container.Get<DbConnection>("baseMap");
2.4 获取单件对象
对于单件(Singleton)的相关概念,大家可以参考设计模式中的模式,在此仅讨论如何用 Unity 来获取单件对象。
在配置文件中的第三个 type 就是单件对象的配置(lifetime="Singleton")。通过下面的代码,我们可以看到 Unity 是否实现了单件对象的获取。
/// <summary>
/// 获取单件对象。
/// </summary>
private static void SingletonMap() {
IUnityContainer container = CreateContainer();
IDbConnection connection = container.Get<IDbConnection>("interfaceSingleton");
connection.ConnectionString = "server=10.99.123.22,...";
Console.WriteLine(connection.ConnectionString);
IDbConnection secodeConnection = container.Get<IDbConnection>("interfaceSingleton");
secodeConnection.ConnectionString = "server=192.168.0.2...";
Console.WriteLine(connection.ConnectionString);
}
效果如下图所示:
由此我们可以看到,虽然获取了二个对象,但事实上通过配置指定, Unity 容器为我们管理了一个单件对象,二个变量实质指向相同的对象引用。
2.5 instances 实例
在配置文件中的 instances 元素的作用相当于使用 Unity 的 RegisterSingleton 方法来注册已有的单件对象。因此,可以使用如下代码来获取配置文件中的定义的二个实例:
/// <summary>
/// instances 元素的示例。
/// </summary>
private static void InstancesExample() {
IUnityContainer container = CreateContainer();
string instances1 = container.Get<string>("MyInstance1");
Console.WriteLine(instances1);
DateTime instances2 = container.Get<DateTime>("MyInstance2");
Console.WriteLine(instances2);
}
可以看出,这与前几个示例的获取代码没有什么区别,所以无论使用哪种方式进行配置,对客户代码来说都是一样的。
3 结束语
因为目前 Unity 还仅是 CTP 版本,所以代码、文档都些 bug 的存在,所以文章的内容可能会与文档的内容不一致,但这是目前正确的使用方法。
示例中的源代码,请在这里下载。
关于 Unity 的方法的详细使用方法,请继续关注我的理想&美人。
希望对您有所帮助!
邓明