Unity 3(二):Unity在AOP方面的应用
本文关注以下方面(环境为VS2012、.Net Framework 4.5以及Unity 3):
- AOP简介;
- Interception using Unity示例
- 配置文件示例
一、AOP简介
AOP为Aspect-Oriented Programming的缩写,意为"面向切面(方面)编程",按维基百科的解释是"AOP is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns" (http://en.wikipedia.org/wiki/Aspect-oriented_programming)。
通俗的理解就是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术,我们可以理解为在一个服务的流程中,插入与该服务的业务逻辑无关的系统服务逻辑(操作前或操作后),如日志记录、安全认证、性能检测等等。
二、Interception using Unity示例
本示例中主要用于展示如何应用Unity实现编程的Interception,更多内容请阅读http://msdn.microsoft.com/en-us/library/dn178466.aspx
还是以一个简单的日志记录程序为例
Console程序如下(以Log为例)
interface ILog { void Log(string message); }
class ConsoleLog : ILog { public void Log(string message) { Console.WriteLine(message); } }
下面我们编写一个切入的用于记录日志的类,当然首先要引入相应的命名空间,Unity Interception Extension可以通过NuGet获取
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Practices.Unity.InterceptionExtension; namespace Demo { class LoggingInterceptionBehavior : IInterceptionBehavior { public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { // Before invoking the method on the original target. WriteLog(String.Format("Invoking method {0} at {1}", input.MethodBase, DateTime.Now.ToLongTimeString())); // Invoke the next behavior in the chain. var result = getNext()(input, getNext); // After invoking the method on the original target. if (result.Exception != null) { WriteLog(String.Format("Method {0} threw exception {1} at {2}", input.MethodBase, result.Exception.Message, DateTime.Now.ToLongTimeString())); } else { WriteLog(String.Format("Method {0} returned {1} at {2}", input.MethodBase, result.ReturnValue, DateTime.Now.ToLongTimeString())); } return result; } public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public bool WillExecute { get { return true; } } private void WriteLog(string message) { Console.WriteLine(message); } } }
为了方便观察多个切入,我们在定义一个PerformanceInterceptionBehavior
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Practices.Unity.InterceptionExtension; namespace PCT.Unity.DIWithUntiy { class PerformanceInterceptionBehavior : IInterceptionBehavior { public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Reset(); stopwatch.Start(); // Invoke the next behavior in the chain. var result = getNext()(input, getNext); // After invoking the method on the original target. if (result.Exception != null) { WriteLog(String.Format("Method {0} threw exception {1} at {2}", input.MethodBase, result.Exception.Message, DateTime.Now.ToLongTimeString())); } else { stopwatch.Stop(); WriteLog(String.Format("Method {0} executed {1}", input.MethodBase, stopwatch.Elapsed)); } return result; } public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public bool WillExecute { get { return true; } } private void WriteLog(string message) { Console.WriteLine(message); } } }
最终控制台的代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Practices.Unity; using Microsoft.Practices.Unity.InterceptionExtension; namespace PCT.Unity.DIWithUntiy { class Program { static void Main(string[] args) { var container = new UnityContainer(); container.AddNewExtension<Interception>(); container.RegisterType<ILog, ConsoleLog>( new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<LoggingInterceptionBehavior>(), new InterceptionBehavior<PerformanceInterceptionBehavior>()); var logger = container.Resolve<ILog>(); logger.Log("Hello, Unity Framework!"); Console.ReadKey(); } } }
运行结果如下
如果我们把代码改成如下
container.RegisterType<ILog, ConsoleLog>( new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<PerformanceInterceptionBehavior>(), new InterceptionBehavior<LoggingInterceptionBehavior>());
再次运行
是不是发现了什么,对,切入的顺序不同,最终执行的顺序也不同。
三、配置文件示例
控制台代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Practices.Unity; using Microsoft.Practices.Unity.Configuration; using Microsoft.Practices.Unity.InterceptionExtension; namespace PCT.Unity.DIWithUntiy { class Program { static void Main(string[] args) { var container = new UnityContainer(); //container.AddNewExtension<Interception>(); //container.RegisterType<ILog, ConsoleLog>( // new Interceptor<InterfaceInterceptor>(), // new InterceptionBehavior<PerformanceInterceptionBehavior>(), // new InterceptionBehavior<LoggingInterceptionBehavior>()); container.LoadConfiguration(); var logger = container.Resolve<ILog>(); logger.Log("Hello, Unity Framework!"); Console.ReadKey(); } } }
配置文件
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/> </configSections> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" /> <alias alias="ILog" type="PCT.Unity.DIWithUntiy.ILog"/> <alias alias="ConsoleLog" type="PCT.Unity.DIWithUntiy.ConsoleLog"/> <alias alias="PerformanceInterceptionBehavior" type="PCT.Unity.DIWithUntiy.PerformanceInterceptionBehavior"/> <alias alias="LoggingInterceptionBehavior" type="PCT.Unity.DIWithUntiy.LoggingInterceptionBehavior"/> <assembly name="PCT.Unity.DIWithUntiy" /> <namespace name="PCT.Unity.DIWithUntiy" /> <container> <extension type="Interception"/> <register type="ILog" mapTo="ConsoleLog"> <interceptor type="InterfaceInterceptor"/> <interceptionBehavior type="LoggingInterceptionBehavior" /> <interceptionBehavior type="PerformanceInterceptionBehavior" /> </register> </container> </unity> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> </configuration>