和 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 元素有下列子元素:
注意:不能嵌套定义容器,即 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 的方法的详细使用方法,请继续关注我的理想&美人。
希望对您有所帮助!
邓明