现在的位置: 首页 > 综合 > 正文

通过定义UnityContainer扩展变”Explicit Interception”为”Automatic Interception”

2012年05月21日 ⁄ 综合 ⁄ 共 4493字 ⁄ 字号 评论关闭

Unity是微软P&P部门开发的一个轻量级IoC框架,通过Interception机制可以实现基于三种拦截机制的AOP。不过Unity仅仅提供“显式”拦截机制,以致我们为了注册可被拦截的类型会多写很多代码和配置。本篇文章通过UnityContainer的扩展提供了一种“自动”拦截机制。

一、显式拦截

我们通过一个简单的实例演示Unity原生支持的显式拦截机制和我们通过扩展实现的自动拦截机制。我们定了如下一个简单的SimpleCallHandler,在Invoke方法中通过在控制台打印一段文字用以证明应用在某个类型上的CallHandler被执行了。

   1: public class SimpleCallHandler : ICallHandler

   2: {

   3:     public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)

   4:     {

   5:         Console.WriteLine("The CallHandler applied to \"{0}\" is invoked.", input.Target.GetType().Name);

   6:         return getNext()(input, getNext);

   7:     }

   8:     public int Order { get; set; }

   9: }

  10: public class SimpleCallHandlerAttribute : HandlerAttribute

  11: {

  12:     public override ICallHandler CreateHandler(IUnityContainer container)

  13:     {

  14:         return new SimpleCallHandler { Order = this.Order };

  15:     }

  16: }

然后我们创建了如下所示的一个接口IFoo和三个类Foo、Bar和Baz。其中Foo实现了接口IFoo,而Foo依赖于Bar,Bar依赖于Baz。我们以构造器注入的方式定义Foo和Bar。SimpleCallHandler被同时应用到了Foo、Bar和Baz的DoSth方法上。

   1: public interface IFoo

   2:    {

   3:        void DoSth();

   4:    }

   5:  

   6:    public class Foo : IFoo

   7:    {

   8:        public Bar Bar { get; private set; }

   9:        public Foo(Bar bar)

  10:        {

  11:            this.Bar = bar;

  12:        }

  13:        [SimpleCallHandler]

  14:        public virtual void DoSth()

  15:        {

  16:            this.Bar.DoSth();

  17:        }

  18:    }

  19:    public class Bar : MarshalByRefObject

  20:    {

  21:        public Baz Baz { get; private set; }

  22:        public Bar(Baz baz)

  23:        {

  24:            this.Baz = baz;

  25:        }

  26:        [SimpleCallHandler]

  27:        public virtual void DoSth()

  28:        {

  29:            this.Baz.DoSth();

  30:        }

  31:    }

  32:    public class Baz : MarshalByRefObject

  33:    {

  34:        [SimpleCallHandler]

  35:        public void DoSth()

  36:        {

  37:            Console.WriteLine("Done...");

  38:        }

  39:    }

所谓显式拦截就是说:如果某个类型需要被拦截处理,比如将其显式地注册为“可被拦截的类型”,并且需要显式地注册拦截器(决定拦截机制)和拦截行为。对于本实例来说,为了上应用在Foo、Bar和Baz上的CallHandler能够起作用,我们需要通过如下的方式对这三个类型进行显式地拦截注册。

   1: IUnityContainer container = new UnityContainer();

   2: container.AddNewExtension<Interception>()

   3:     .RegisterType<IFoo, Foo>(new Interceptor<TransparentProxyInterceptor>(), new InterceptionBehavior<PolicyInjectionBehavior>())

   4:     .RegisterType<Bar>(new Interceptor<TransparentProxyInterceptor>(), new InterceptionBehavior<PolicyInjectionBehavior>())

   5:     .RegisterType<Baz>(new Interceptor<TransparentProxyInterceptor>(), new InterceptionBehavior<PolicyInjectionBehavior>());

   6:  

   7: IFoo foo = container.Resolve<IFoo>();

   8: foo.DoSth();

运行结果:

   1: The CallHandler applied to "Foo" is invoked.

   2: The CallHandler applied to "Bar" is invoked.

   3: The CallHandler applied to "Baz" is invoked.

   4: Done...

二、自动拦截

如果通过我们自定义的UnityContainer扩展AutoInterception,你就无须对需要被拦截的类型进行显式注册。而相关的代码将会变得简单,运行如下一段代码,你依然会得到同上面一样的结果。

   1: IUnityContainer container = new UnityContainer();

   2: container.AddNewExtension<AutoInterception>()

   3:     .AddNewExtension<Interception>()

   4:     .RegisterType<IFoo, Foo>();

   5:  

   6: IFoo foo = container.Resolve<IFoo>();

   7: foo.DoSth();

三、应用不同的拦截机制

在默认的情况下,AutoInterception采用的拦截器为TransparentProxyInterceptor。我们通过通过配置AutoInterception的方式来应用其它两种拦截器,即InterfaceInterceptor和VirtualMethodInterceptor。由于在下面的代码中采用了InterfaceInterceptor,所有只有实现了IFoo接口的Foo对象才会被拦截。

   1: IUnityContainer container = new UnityContainer();

   2: container.AddNewExtension<AutoInterception>()

   3:     .AddNewExtension<Interception>()

   4:     .Configure < AutoInterception>().RegisterInterceptor(new InterfaceInterceptor())

   5:     .RegisterType<IFoo, Foo>();

   6:  

   7: IFoo foo = container.Resolve<IFoo>();

   8: foo.DoSth();

执行结果:

   1: The CallHandler applied to "Foo" is invoked.

   2: Done...

如果我们采用VirtualMethodInterceptor的话,只有定义在需方法的Foo和Bar的DoSth方法才会被拦截。

   1: IUnityContainer container = new UnityContainer();

   2: container.AddNewExtension<AutoInterception>()

   3:     .AddNewExtension<Interception>()

   4:     .Configure < AutoInterception>().RegisterInterceptor(new VirtualMethodInterceptor())

   5:     .RegisterType<IFoo, Foo>();

   6:  

   7: IFoo foo = container.Resolve<IFoo>();

   8: foo.DoSth();

输出结果:

   1: The CallHandler applied to "Wrapped_Foo_6c22528df1b64d3886e9955cd8961ca7" is invoked.

   2: The CallHandler applied to "Wrapped_Bar_c10e3640a27d469c8872ec4193303897" is invoked.

   3: Done...

四、支持配置

AutoInterception不仅仅支持Unity提供的Policy Injection配置,还可以通过配置指定采用的拦截器类型。现在我们将应用在Foo、Bar和Baz上的SimpleCallHandlerAttribute特性全部删除,通过如下的配置将该CallHandler应用到所有的DoSth方法上。这个配置还指定了采用的拦截器类型为VirtualMethodInterceptor。

   1: <?xml version="1.0" encoding="utf-8" ?>

   2: <configuration>

   3:   <configSections>

   4:     <section name="unity" 

   5:              type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>

   6:     </configSections>

   7:   <unity>

   8:     <alias alias="SimpleCallHandler" type="Artech.UnityExtensions.SimpleCallHandler, Artech.UnityExtensions" />

   9:     <alias alias="IFoo" type="Artech.UnityExtensions.IFoo, Artech.UnityExtensions" />

  10:     <alias alias="Foo" type="Artech.UnityExtensions.Foo, Artech.UnityExtensions" />

  11:     <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" 

抱歉!评论已关闭.