C#使用Castle实现AOP面向切面编程
转自:C#使用Castle实现AOP面向切面编程 - 以德为先 - 博客园 (cnblogs.com)
Castle.Core 本质是创建继承原来类的代理类,重写虚方法实现AOP功能。个人觉得比Autofac用着爽
使用方式比较简单,先新建一个控制台项目,然后在Nuget上搜索Castle.Core并安装,如下顺序:
或者通过命令安装:
Install-Package Castle.Core -Version 3.3.3
安装成功之后,如下图:
1. 创建拦截器
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; //先在Nuget上搜索Castle安装 using Castle.DynamicProxy; namespace CastleDEMO { /// <summary> /// 拦截器 需要实现 IInterceptor接口 Intercept方法 /// </summary> public class DA_LogInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { try { DateTime begin = DateTime.Now; Console.WriteLine("开始DAL {0}调用!", invocation.Method.Name); //在被拦截的方法执行完毕后 继续执行 invocation.Proceed(); DateTime end = DateTime.Now; Console.WriteLine("结束DAL {0}调用!耗时:{1}ms", invocation.Method.Name, (end - begin).TotalMilliseconds); } catch (Exception ex) { string methodName = "DA_" + invocation.TargetType.ToString() + "." + invocation.Method.Name; Console.WriteLine("{0}方法错误:{1}", methodName, ex.Message); //如果没有定义异常处理返回值,就直接抛异常 if (!invocation.Method.IsDefined(typeof(ExceptionReturnAttribute), false)) throw; var ls = invocation.Method.GetCustomAttributes(typeof(ExceptionReturnAttribute), false); if (null == ls || ls.Length <= 0) throw; ExceptionReturnAttribute v = (ExceptionReturnAttribute)ls[0]; if (null == v.Value && null == v.Type) { invocation.ReturnValue = null; return; } if (null != v.Value) { invocation.ReturnValue = v.Value; return; } if (null != v.Type) { invocation.ReturnValue = Activator.CreateInstance(v.Type); return; } } } /// <summary> /// <para>DAO层异常时,不throw,返回设定的值.</para> /// <para>1. 返回复杂类型,使用Type,复杂类型需要有无参的构造函数</para> /// <para>2. 返回简单类型,使用value</para> /// </summary> [AttributeUsage(AttributeTargets.Method)] public class ExceptionReturnAttribute : System.Attribute { /// <summary> /// 返回复杂类型,使用Type,复杂类型需要有无参的构造函数 /// </summary> public Type Type { get; set; } /// <summary> /// 返回简单类型,使用value /// </summary> public object Value { get; set; } } } }
2. 创建拦截容器
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Castle.DynamicProxy; namespace CastleDEMO { /// <summary> /// Dao 类的接口 /// 继承实现BaseDao的类,其相关接口访问的公共方法必须要声明 virtual 方法才能被拦截器拦截。 /// </summary> public abstract class BaseDao { } /// <summary> /// Dao容器,必须依赖于此类来创建Dao对象,使Dao受控,可进行检查等 /// </summary> public class DaoContainer { //ProxyGenerator上自身有缓存 //实例化【代理类生成器】 public static ProxyGenerator generator = new ProxyGenerator(); public static T GetDao<T>() where T : BaseDao { //实例化【拦截器】 DA_LogInterceptor interceptor = new DA_LogInterceptor(); //使用【代理类生成器】创建T对象,而不是使用new关键字来实例化 return generator.CreateClassProxy<T>(interceptor); } } }
3. 新建实例类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CastleDEMO { public abstract class PersonDAL : BaseDao { /// <summary> /// 必须是虚方法才能被拦截器拦截 /// </summary> public virtual void SayHello() { Console.WriteLine("我是虚方法{0}方法", "SayHello"); } public virtual void SayName(string name) { Console.WriteLine("我是虚方法{0}方法,参数值:{1}", "SayName", name); } public abstract void AbstactSayOther(); public void SayOther() { Console.WriteLine("我是普通方法{0}方法", "SayOther"); } } }
4. 测试
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CastleDEMO { public class Program { public static void Main(string[] args) { PersonDAL person = DaoContainer.GetDao<PersonDAL>(); Console.WriteLine("当前类型:{0},父类型:{1}", person.GetType(), person.GetType().BaseType); Console.WriteLine(); person.SayHello();//拦截 Console.WriteLine(); person.SayName("Never、C");//拦截 Console.WriteLine(); person.SayOther();//普通方法,无法拦截 //person.AbstactSayOther();//抽象方法,可以拦截(但是如果方法没实现拦截时会报错) Console.ReadLine(); } } }