C#使用Castle实现AOP面向切面编程

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();
        }
    }
}

posted @ 2018-12-05 16:39  以德为先  阅读(5878)  评论(0编辑  收藏  举报