成长的足迹.NET

我的.NET成长之路

 

Unity 1.2使用初探[转]

最近赋闲在家,突然想看一点东西。

以前都有用Enterprise Library,对于PolicyInject可使项目辅助功Log,Auth等以更优雅的方式,叹其巧妙。现在微软出了Unity1.2注入容器,但是我在使用这个框架上还是个新手,所以在此学习如何应用。(下载地址: http://www.codeplex.com/unity )

下面是我的一些初步使用,主要参照在 UnityDocs,路过的各位高手哪位有比较完好的中午资料,请是否可共享一下~~;

1,第一个Demo;

以下是一个Demo:首先定义1个接口,1个实现:

 

public interface ILogService

{

void Write(string message);

}

 

public class CnsLogService: ILogService

{

#region ILogService 成员

 

public void Write(string message) {

Console.WriteLine(String.Format("Cns-exception msg:{0}", message));

}

 

#endregion

}

 

然后我们可以这样应用Unity:

public static void Main(string[] args) {

 

IUnityContainer myContainer = new UnityContainer();

myContainer.RegisterType<ILogService, CnsLogService>();

ILogService myServiceInstance = myContainer.Resolve<ILogService>();

myServiceInstance.Write("oh,exception occured!");

}

运行结果如下图:

 

2, 注入链

发现文档有这样一段内容

大体意思就是你可以注册一连串的类型。代码如上所示:

那么来实现一下:

先再实现一次ILogService

public class DataLogService:ILogService

{

#region ILogService 成员

 

public void Write(string message) {

DailyPractice.Utility.Log.AddLog(message);

}

 

#endregion

}

 

namespace DailyPractice.Utility

{

public class Log

{

public static void AddLog(string message) {

//insert into Log(message) values(@message)

Console.WriteLine(String.Format("Data-exception msg:{0}", message));

}

}

}

 

然后实现一下注册:

public static void Main(string[] args) {

IUnityContainer myContainer = new UnityContainer();

myContainer.RegisterType<ILogService, CnsLogService>()

.RegisterType<ILogService, DataLogService>();

ILogService myServiceInstance = myContainer.Resolve<ILogService>();

myServiceInstance.Write("oh,exception occured!");

 

}

结果执行为:

非常意外: CnsLogService并没有执行

然后把代码改成

public static void Main(string[] args) {

IUnityContainer myContainer = new UnityContainer();

myContainer.RegisterType<ILogService, CnsLogService>()

.RegisterType<ILogService, DataLogService>();

IEnumerable<ILogService> myServiceInstances = myContainer.ResolveAll<ILogService>();

foreach (ILogService myServiceInstance in myServiceInstances) { myServiceInstance.Write("haha, you have an exception 了吧!"); }

}

执行结果是:

什么都没有执行???

看过terrylee的blog:http://www.cnblogs.com/terrylee/archive/2008/02/21/unity-application-block-part1.html

发现还有一种实现方式,先看代码:

public static void Main(string[] args) {

IUnityContainer myContainer = new UnityContainer();

myContainer.RegisterType<ILogService, CnsLogService>("CnsLogService")

.RegisterType<ILogService, DataLogService>("DataLogService");

IEnumerable<ILogService> myServiceInstances = myContainer.ResolveAll<ILogService>();

foreach (ILogService myServiceInstance in myServiceInstances) { myServiceInstance.Write("haha, you have an exception 了吧!"); }

}

执行结果是:

执行结果正常,

所以现在就来找原因:terrylee's blog有这么一段

    除了可以获取单个对象实例之外,我们还可以一次获取容器中所有与某一接口映射的所有对象实例,但是需要依赖于在注册映射时提供的名称,如果没有指定名称,通过GetAll方法不会被获取到。

 

继续,我们主要编码的形式展示了Unity的编码方式实现。下面我们讲讨论使用配置文件实现。

这里我们继续使用上节的代码:

namespace DailyPractice.UnityEx

{

public interface ILogService

{

void Write(string message);

}

 

public class CnsLogService: ILogService

{

#region ILogService 成员

 

public void Write(string message) {

Console.WriteLine(String.Format("Cns-exception msg:{0}", message));

}

#endregion

}

 

public class DataLogService:ILogService

{

#region ILogService 成员

 

public void Write(string message) {

DailyPractice.Utility.Log.AddLog(message);

}

#endregion

}

}

 

namespace DailyPractice.Utility

{

public class Log

{

public static void AddLog(string message) {

//insert into Log(message) values(@message)

Console.WriteLine(String.Format("Data-exception msg:{0}", message));

}

}

}

这段代码主要实现了ILogService接口,然后我们以配置文件去实现,编写如下的配置文件:

<?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="One">

<types>

<type type="DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx"

mapTo="DailyPractice.UnityEx.DataLogService, DailyPractice.UnityEx"/>

</types>

</container>

</containers>

</unity>

</configuration>

这里我进行相关的说明,configSections配置节的是unity固定配置,通过配置文件实现Unity,先要进行此配置:

<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />

然后,我们在看<unity>里面的配置:

<containers>是必须元素,其内可有多container个元素,container元素就是每一个容器的配置,它有一个可选的 name属性,用于指定容器的名称。

container元素有下列子元素: types元素 ,instances元素, extensions元素。

这里主要说type元素,在文档中有这么一句:

The type element defines a type mapping for the Unity container. If you specify a name, that name is used for the type mapping. If you do not specify a name, it creates a default mapping for the specified types. You can specify a lifetime manager for each mapping. If no explicit lifetime manager is configured for a type, transient lifetime management is exercised.

大致的意思就是或type元素定义了一个指向的type,如果你指定了一个name,那么就以你指定的来mapping,否则则创建一个一个默认的mapping for the specified types,你还可以指定lifetime manager,如果你不指定,将应用transient lifetime management

mapTo是: The actual Type object for the mapTo element in the configuration file.

所以根据以上,可以知道我们是在以 DataLogService 进行 container映射。

 

然后就是代码实现了:

namespace DailyPractice.UnityEx

{

public class UnityConfigEx

{

public static void Main() {

IUnityContainer myContainer = new UnityContainer();

UnityConfigurationSection section

= (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

section.Containers[0].Configure(myContainer);

 

ILogService myServiceInstance = myContainer.Resolve<ILogService>();

myServiceInstance.Write("oh,exception occured!");

}

}

}

执行结果为:

如果我们这样更改配置节:

<?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="One">

<types>

<type type="DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx"

mapTo="DailyPractice.UnityEx.CnsLogService, DailyPractice.UnityEx"/>

<!--<type type="DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx"

mapTo="DailyPractice.UnityEx.DataLogService, DailyPractice.UnityEx"/>-->

</types>

<instances></instances>

<extensions></extensions>

</container>

</containers>

</unity>

</configuration>

执行结果为:

如果两个都配置呢?那么我们更改配置文件:

<?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="One">

<types>

<type type="DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx" name="cnslogger"

mapTo="DailyPractice.UnityEx.CnsLogService, DailyPractice.UnityEx"/>

<type type="DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx" name="datalogger"

mapTo="DailyPractice.UnityEx.DataLogService, DailyPractice.UnityEx"/>

</types>

<instances></instances>

<extensions></extensions>

</container>

</containers>

</unity>

</configuration>

修改程序代码:

namespace DailyPractice.UnityEx

{

public class UnityConfigEx

{

public static void Main() {

IUnityContainer myContainer = new UnityContainer();

UnityConfigurationSection section

= (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

section.Containers[0].Types[0].Configure(myContainer);

section.Containers[0].Types[1].Configure(myContainer);

 

IEnumerable<ILogService> myServiceInstances = myContainer.ResolveAll<ILogService>();

foreach (ILogService myServiceInstance in myServiceInstances) {

myServiceInstance.Write("haha, you have an exception 了吧!");

}

myContainer.Dispose();

}

}

}

运行结果:

这里我强调一下:配置节name="cnslogger",在刚刚开始,我没有指定了,结果报错如下

The entry ':DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx' has already been added. (D:\Project\ProjectEx\DailyPractice\UnityEx\bin\Debug\DailyPractice.UnityEx.vshost.exe.config line 22)

因为Unity有以下源码

protected override object GetElementKey(ConfigurationElement element)

{

UnityTypeElement typeElement = (UnityTypeElement)element;

if (typeElement.Name == null)

{

return typeElement.TypeName;

}

 

return typeElement.Name + ":" + typeElement.TypeName;

}

如果不指定name,那么两个type在循环时就会导致GetElementKey都返回了':DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx'结果,导致实例化UnityConfigurationSection异常。

指定name,那么这两次实例化分别是:

cnslogger:DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx

datalogger:DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx

UnityConfigurationSection即可实现正确实例化。

 

 

posted on 2010-03-09 17:15 ejiyuan 阅读(259) 评论(0) 编辑 收藏

导航

统计

公告