.NET中使用unity实现aop

Unity是一款知名的依赖注入容器,其支持通过自定义扩展来扩充功能。在Unity软件包内默认包含了一个对象拦截(Interception)扩展定义。本篇文章将介绍如何使用对象拦截功能来帮助你分离横切关注点(Separation of cross-cutting concerns)。

对象拦截简介

对象拦截是一种AOP(Aspect-oriented programming)编程的实践方法。其可帮助你保持业务类的纯净,而无需考虑诸如日志和缓存等外围关注点。

在.NET中,实现AOP有多种方法。一种方式是采用编译后处理方式,例如PostSharp。在编译后,PostSharp通过修改IL代码来诸如横切代码。

相反地,对象拦截是在运行时执行的,同时也意味着会有一些限制。依据不同的拦截器实现,会有如下这些约束:

  • 透明代理拦截器:需要定义接口,或者要求类继承自MarshalByRefObject。
  • 接口拦截器:需要定义接口。
  • 虚方法拦截器:仅需要方法被定义成virtual方法。

对象拦截如何工作

当从Unity容器请求目标对象时,将不会获取到已配置的类的实例。实际上,将得到一个动态生成的代理对象,或者一个衍生类。

如果调用代理对象的一个方法,将可以在被调用方法执行前或执行后执行一些额外行为的代码。那些定义行为的类需要实现ICallHandler接口。通过这些行为定义,我们可以访问方法调用的参数列表,可以吞噬异常,或者可以返回自定义的异常。

附带提一下,在不使用Unity容器的条件下,也是可以使用Unity拦截器的。

示例:将异常和方法调用参数列表记录到日志中

在下面的示例中,我们将创建两个自定义的行为,都实现了ICallHandler接口:

  • LoggerCallHandler:将方法调用参数列表记录到日志中。
  • ExceptionLoggerCallHandler:将方法调用参数列表和异常信息及调用栈记录到日志中。

ExceptionLoggerCallHandler定义如下:

复制代码
 1   internal class ExceptionLoggerCallHandler : ICallHandler
 2  {  3 public IMethodReturn Invoke(  4  IMethodInvocation input, GetNextHandlerDelegate getNext)  5  {  6 IMethodReturn result = getNext()(input, getNext);  7 if (result.Exception != null)  8  {  9 Console.WriteLine("ExceptionLoggerCallHandler:"); 10 Console.WriteLine("\tParameters:"); 11 for (int i = 0; i < input.Arguments.Count; i++) 12  { 13 var parameter = input.Arguments[i]; 14  Console.WriteLine( 15 string.Format("\t\tParam{0} -> {1}", i, parameter.ToString())); 16  } 17  Console.WriteLine(); 18 Console.WriteLine("Exception occured: "); 19  Console.WriteLine( 20 string.Format("\tException -> {0}", result.Exception.Message)); 21 22  Console.WriteLine(); 23 Console.WriteLine("StackTrace:"); 24  Console.WriteLine(Environment.StackTrace); 25  } 26 27 return result; 28  } 29 30 public int Order { get; set; } 31 }
复制代码

为了将行为应用到方法上,我们需要创建相应的HandlerAttribute来创建行为的实例。

复制代码
1   internal class ExceptionLoggerAttribute : HandlerAttribute
2  { 3 public override ICallHandler CreateHandler(IUnityContainer container) 4  { 5 return new ExceptionLoggerCallHandler(); 6  } 7 }
复制代码

在这个示例中,我们创建一个简单的计算器类。同时为了使用接口拦截功能,我们还需创建一个接口类型,这样才能应用指定的行为:

复制代码
1   public interface ICalculator
2  { 3  [Logger] 4 int Add(int first, int second); 5 6  [ExceptionLogger] 7 int Multiply(int first, int second); 8 }
复制代码

计算器类的实现还和常规的一样。现在我们需要配置Unity容器:

复制代码
 1       IUnityContainer container = new UnityContainer();
 2       container.AddNewExtension<Interception>();
 3  container  4 .RegisterType<ICalculator, Calculator>()  5 .Configure<Interception>()  6 .SetInterceptorFor<ICalculator>(new InterfaceInterceptor());  7  8 // Resolve  9 ICalculator calc = container.Resolve<ICalculator>(); 10 11 // Call method 12 calc.Add(1, 2);
复制代码

当在容器上通过调用Resolve方法来尝试获得一个Calculate类的实例时,将会得到一个代理类实例。它的名字可能类似于 ‘DynamicModule.ns.Wrapped_ICalculator_83093f794c8d452e8af4524873a017de’。当调用此包装类的某个方法时,CallHandlers将会被执行。

总结

Unity并不提供一个完整的AOP框架,因此使用它会有一些限制。但不管怎样,使用Unity对象拦截功能来实现一些基本的AOP需求已经足够了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值