在本文中,將研究Unity 配置文件的格式、配置的讀取、通過示例說明實例的獲取。
1. Unity 配置文件的完整格式
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration, Version=1.0.0.0,Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </configSections> <unity> <typeAliases> <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,Microsoft.Practices.Unity" /> <typeAlias alias="external" type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager, Microsoft.Practices.Unity" /> <typeAlias alias="IMyInterface" type="MyApplication.MyTypes.MyInterface, MyApplication.MyTypes" /> <typeAlias alias="MyRealObject" type="MyApplication.MyTypes.MyRealObject, MyApplication.MyTypes" /> <typeAlias alias="IMyService" type="MyApplication.MyTypes.MyService, MyApplication.MyTypes" /> <typeAlias alias="MyDataService" type="MyApplication.MyTypes.MyDataService, MyApplication.MyTypes" /> <typeAlias alias="MyCustomLifetime" type="MyApplication.MyLifetimeManager, MyApplication.MyTypes" /> </typeAliases> <containers> <container name="containerOne"> <types> <type type="Custom.MyBaseClass" mapTo="Custom.MyConcreteClass" /> <type type="IMyInterface" mapTo="MyRealObject" name="MyMapping" /> <type type="Custom.MyBaseClass" mapTo="Custom.MyConcreteClass"> <lifetime type="singleton" /> </type> <type type="IMyInterface" mapTo="MyRealObject" name="RealObject"> <lifetime type="external" /> </type> <type type="Custom.MyBaseClass" mapTo="Custom.MyConcreteClass"> <lifetime value="sessionKey" type="MyApplication.MyTypes.MyLifetimeManager,MyApplication.MyTypes" /> </type> <type type="IMyInterface" mapTo="MyRealObject" name="CustomSession"> <lifetime type="MyCustomLifetime" value="ReverseKey" typeConverter="MyApplication.MyTypes.MyTypeConverter,MyApplication.MyTypes" /> </type> <type type="IMyService" mapTo="MyDataService" name="DataService"> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration"> <constructor> <param name="connectionString" parameterType="string"> <value value="AdventureWorks"/> </param> <param name="logger" parameterType="ILogger"> <dependency /> </param> </constructor> <property name="Logger" propertyType="ILogger" /> <method name="Initialize"> <param name="connectionString" parameterType="string"> <value value="contoso"/> </param> <param name="dataService" parameterType="IMyService"> <dependency /> </param> </method> </typeConfig> </type> </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> <extensionConfig> <add name="MyExtensionConfigHandler" type="MyApp.MyExtensions.SpecialOne.ConfigHandler" /> </extensionConfig> </container> </containers> </unity> </configuration>
看到上面的內容好多人會感到怎麼這麼複雜啊?實際上,上面的內容是一個完整的結構,以供參考,在日常開發中一般不會全用到的,這裏用的最多的元素標記是:<containers>中的<container>內部的<type>標記。
Unity的配置節的名稱爲”Unity",節處理程序的類型爲 Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,它包含在程序集 Microsoft.Practices.Unity.Configuration 中。所在應當在網站是添加該程序集的引用。
unity 的子元素包含了一個 containers 元素,containers 元素可以包含若干個 container 元素。container 元素就是每個容器的配置,它有一個可選的 name 屬性,用於指定容器的名稱。
<types> 元素是 container 元素的子元素之一。包含任意數量的 type元素,用以添加類型註冊,這些配置被container.RegisterType<TFrom,TTo>()註冊;
type元素的屬性。
name:在註冊此類型時使用的名稱。此屬性是可選的,如果不指定此屬性,所在的 add 元素即爲默認的類型映射。
type:容器中配置的源類型。如果這是映射註冊,這就是映射的起始對象的類型;如果這是單件註冊,這就是對象的類型。此屬性是必須的。
mapTo:類型映射的目標類型。如果這是映射註冊,這就是映射的目標對象的類型。此屬性是可選的。
lifetime:設置用於給定的類型和名稱的生命週期。是一個來自 LifetimeStyle 枚舉的值。有效的值是 Transient(默認),它導致了容器每次都創建一個新的實例;以及 Singleton,它使容器爲每個請求返回同一實例。如果在配置一個單件時同時指定了 type 和 mapto 屬性,SetSingleton 方法將返回指定在 mapTo 屬性中的類型。如果 mapTo 屬性沒有指定值,SetSingleton 方法將返回指定在 type 屬性中的類型。
<instances> 元素保持了用於此容器的已有對象實例的列表。這些對象被用容器的 RegisterInstance 方法進行註冊。instances 元素包含了一系列添加單個實例的 add 元素。
add 元素的屬性。
name:註冊此實例時使用的名稱。此屬性是可選的。
type:此實例的類型。此屬性是可選的。如果忽略,假定的類型是 System.String。
value:用於初始化實例的值。此屬性是必須的。
typeConverter:用以轉換提供的值到實例的匹配類型的類型轉換器。如果沒有指定,將使用指定類型的默認轉換器。此屬性是可選的。
<typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement,Microsoft.Practices.Unity.Configuration">
用來配置在類型註冊時,構造函數依賴注入,屬性依賴注入和方法依賴注入時的對象初始化信息。它包含以下幾個子元素:
<constructor> <param name="connectionString" parameterType="string"> <value value="AdventureWorks"/> </param> <param name="logger" parameterType="ILogger"> <dependency /> </param> </constructor> <property name="Logger" propertyType="ILogger" /> <method name="Initialize"> <param name="connectionString" parameterType="string"> <value value="contoso"/> </param> <param name="dataService" parameterType="IMyService"> <dependency /> </param> </method>
在執行Container.Resolve()生成對象實例的時候,會根據上面的配置信息的內容對要生成的對象進行依賴注入。
二、加載配置信息到容器中
1、加載一個單獨的未命名容器或規定了默認容器:
IUnityContainer container = new UnityContainer(); UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Containers.Default.Configure(container);
這樣就會根據配置文件中的配置信息,在UnityContainer容器中註冊類型映射
2、加載一個特殊命名容器的配置信息,需要使用定義在配置文件中的容器名,而不是引用默認容器。例如,如果在配置中有一個命名爲containerOne的容器,能使用如下代碼初始化並加載它:
IUnityContainer container = new UnityContainer(); UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Containers["containerOne"].Configure(container);
3、爲了從配置信息中創建一個嵌套容器繼承, 可以簡單的使用CreateChildContainer方法在你需要的繼承深度中創建容器對象,然後通過讀取各自的配置文件加載合適的配置。下面的代碼展示瞭如何從配置文件中實例化和加載兩個容器,這個配置文件同時包含了針對兩個命名爲containerOne和newstedChildContainer容器的註冊信息,類型映射和擴展定義。
IUnityContainer parentContainer = new UnityContainer(); IUnityContainer childContainer = parentContainer.CreateChildContainer(); UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Containers["containerOne"].GetConfigCommand().Configure(parentContainer); section.Containers["nestedChildContainer"].Configure(childContainer);
三、從容器的映射信息生成對象實例:
這裏依然還是用UnityContainer類的Resolve方法來實現的。在此不多說了。
四、一個簡單的例子:
1、類的結構:
public abstract class Player { public abstract string Play(); } public class MP3Player : Player { public override string Play() { return ("this is a MP3Player"); } } public class CDPlayer : Player { public override string Play() { return ("this is a CDPlayer"); } } public class DVDPlayer : Player { public override string Play() { return ("this is a DVDPlayer"); } }
2、Web.Config文件的配置
<configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/> </configSections> <unity> <containers> <container> <types> <type type="Player,App_Code" mapTo="MP3Player,App_Code"></type> </types> </container> </containers> </unity>
3、客戶代碼的實現:
IUnityContainer container = new UnityContainer(); UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Containers.Default.Configure(container); Player p = container.Resolve<Player>(); Response.Write(p.Play());