ASP.NETCore 切面编程AOP 详解

一.AOP概述:

  AOP(Aspect Oriented Programming),即面向切面编程。采用“横切”的思想,将软件系统的系统功能业务功能分开。

  系统功能主要有

    1.缓存模块:用于缓存数据,与系统业务功能关系不大,用于提升系统性能。当数据请求过来时,是否要从缓存读取,当缓存没有数据时,

       是否要将获取到的数据放入缓存,以便下次数据请求时从缓存读取。比较常用的缓存工具有monogodb,redis。

    2.验证模块:判断当前用户是否有获取该条数据 或者执行 该操作的权限。

    3.日志模块:收集当前用户的操作痕迹,或者记录系统出现的问题,后期可进行大数据行为分析。

       业务功能:系统处理用户请求的正常逻辑功能。

       http请求过来后,会先经过系统功能的横切拦截,才会到业务功能处理请求。AOP具体过程如下图所示:

         

二、AOP实现:

  国内大佬基于.NETStand 实现了一个AOP的框架,其源码地址为  https://github.com/dotnetcore/AspectCore-Framework

  要使用该框架,可通过Nuget 将 AspectCore.Extensions.DependencyInjection 引用到项目中,可实现日志拦截和缓存拦截,该框架是基于IOC容器的。

     这里,我用控制台程序来演示:首先,先nuget 引用 AspectCore.Extensions.DependencyInjection。

  1.程序入口:     

class Program
    {
        static void Main(string[] args)
        {
            //创建用于注册服务的IOC容器 ServiceCollection
            ServiceCollection services = new ServiceCollection();

            //在容器中 注册服务
            services.ConfigureDynamicProxy();
            services.AddScoped<IMySql, MySql>();

            //创建ServiceProvider,用于获取服务。
            var provider = services.BuildDynamicProxyProvider();

            //获取服务。
            var mysql = provider.GetService<IMySql>();
            
            //执行服务。
            var msg=mysql.GetById(10);

            //第一次去数据,从业务逻辑取数据
            var value = mysql.GetData("hehe");
            Console.WriteLine(value);

            //第二次去数据,从缓存取
            value = mysql.GetData("hehe");
            Console.WriteLine(value);

            Console.ReadKey();
            Console.WriteLine("Hello World!");
        }
    }

  2.系统功能 切面部分(AOP):

     日志切面:

    /// <summary>
    /// 日志模块:(日志切面,日志AOP)
    /// </summary>
    public class MyLogInterceptorAttribute : AbstractInterceptorAttribute
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context">委托的参数,这里传递的是 GetById 方法</param>
        /// <param name="next">委托,委托的动作要看具体传进来的方法的动作是什么</param>
        /// <returns></returns>
        public override Task Invoke(AspectContext context, AspectDelegate next)
        {
            Console.WriteLine("开始记录日志.......");

            //var aa = context;
            //var bb = next;
            var task = next(context);//从这里开始执行具体的方法。这里执行的是 GetById;
            Console.WriteLine("结束记录日志.......");
            return task;
        }
    }

   缓存切面:

public class MyCacheInterceptorAttribute : AbstractInterceptorAttribute
    {
        //用于模拟缓存
        private Dictionary<string, string> CacheDic = new Dictionary<string, string>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context">委托的参数,这里传递的是 GetById 方法</param>
        /// <param name="next">委托,委托的动作,要看具体传进来的方法的动作是什么</param>
        /// <returns></returns>
        public override Task Invoke(AspectContext context, AspectDelegate next)
        {
            //获取 传递过来的AspectContext,即传进来的方法 的参数。
            var cacheKey = string.Join(",", context.Parameters);

            //从缓存去数据。如果缓存有,则返回
            if (CacheDic.ContainsKey(cacheKey))
            {
                context.ReturnValue = CacheDic[cacheKey].ToString();
                return Task.CompletedTask;
            }

            //缓存没有,从业务逻辑取数据,去到数据后,将数据放入缓存
            var task = next(context);
            var cacheValue = context.ReturnValue.ToString();
            CacheDic.Add(cacheKey, "From cache:"+cacheValue);

            return task;
        }
    }

  

  3.业务功能部分:

    public interface IMySql
    {
        string GetById(int id);
        string GetData(string key);
    }

    public class MySql : IMySql
    {
        [MyLogInterceptor] //日志切面
        public string GetById(int id)
        {
            var msg = $"已经获取到ID为{id}的数据";
            Console.WriteLine(id);
            return msg;
        }

        [MyCacheInterceptor] //缓存切面
        public string GetData(string key)
        {
            return "获取数据";
        }
    }
原文地址:https://www.cnblogs.com/Fengyinyong/p/13664311.html