首页 > 编程语言 >在aspnetcore中实现AOP的方式

在aspnetcore中实现AOP的方式

时间:2023-03-24 11:22:33浏览次数:54  
标签:Task 方式 aspnetcore await next context AOP var public

aaspnetcore开发框架中实现aop不仅仅在业务上,在代码的优雅简洁和架构的稳定上都有着至关重要。

下面介绍三种用过的。

 

第一种使用DispatchProxy实现

通过使用System.Reflection的DispatchProxy类来实现

首先新建一个aspnetcore项目

 

针对业务代码WarService加了一个代理的方法

复制代码
public interface IWarService
    {
        string WipeOut();
        IWarService Proxy(IWarService warService);
    }


 public class WarService : IWarService
    {
        public IWarService Proxy(IWarService warService)
        {
            return WarDispatch<IWarService>.Create(warService);
        }

        public string WipeOut()
        {
            return "us is over";
        }
    }
复制代码

具体的WarDispatch就是核心代码了,继承自DispatchProxy。这里的before和after的实现就是针对实现了代码的service提前挖坑。

复制代码
public class WarDispatch<T> : DispatchProxy where T : class
    {
        private T Target { get; set; }
        public static T Create<T>(T target) where T : class
        {
            var proxy = Create<T, WarDispatch<T>>() as WarDispatch<T>;
            proxy.Target = target;
            return proxy as T;
        }

        protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
        {
            Before().Wait();
            var result = targetMethod.Invoke(Target, args);
            After().Wait();
            return result;
        }

        Task Before()
        {
            return Task.CompletedTask;
        }

        Task After()
        {
            return Task.CompletedTask;
        }
    }
复制代码

实现代码也相当简单

复制代码
[ApiController]
    [Route("[controller]")]
    public class RescueEarthController : ControllerBase
    {
        private IWarService _warService;
        
        public RescueEarthController(IWarService warService)
        {
            _warService = warService;
        }

        [HttpGet(Name = "AnnihilateHegemony")]
        public string AnnihilateHegemony()
        {
            var proxy = _warService.Proxy(_warService); //代理
            return proxy.WipeOut();
        }

        [HttpGet("two")]
        public string AnnihilateHegemonyTwo()
        {
            return _warService.WipeOut();
        }
    }
复制代码

当然不要忘了注入下服务类

builder.Services.AddScoped<IWarService, WarService>();

上面的方式是我自己想出来的,具体到项目中需要改进的地方应该还有很多,但是足够简单,功能也比较单一。

 第二种使用DynamicProxy实现

下面简单介绍下AspectCore.DynamicProxy现成组件的代理使用。

首先引用aspnetcore.extensions.dependencyinjection包

在program中使用动态代码

 builder.Host.UseServiceProviderFactory(new DynamicProxyServiceProviderFactory());
            builder.Services.ConfigureDynamicProxy(o =>{ 
            //添加aop的配置
            //该项目用attribute所以无需配置
           
            });

内存的缓存代理

复制代码
 public class CacheDeleteInterceptorAttribute:AbstractInterceptorAttribute
    {
        private readonly Type[] _types;
        private readonly string[] _methods;
        public CacheDeleteInterceptorAttribute(Type[] types, string[] methods)
        {
            if (types.Length != methods.Length)
            {
                throw new Exception("Types必须跟Methods数量一致");
            }
            _types = types;
            _methods = methods;
        }

        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            var cache = context.ServiceProvider.GetService<MemoryCache>();
            await next(context);
            for (int i = 0; i < _types.Length; i++)
            {
                var type = _types[i];
                var method = _methods[i];
                string key = "Methods:" + type.FullName + "." + method;
                cache.Remove(key);
            }
        }
    }
复制代码 复制代码
 public class CacheInterceptorAttribute : AbstractInterceptorAttribute
    {
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            bool isAsync = context.IsAsync();
            var methodReturnType = context.GetReturnParameter().Type;
            if(methodReturnType==typeof(void)|| methodReturnType==typeof(Task) || methodReturnType == typeof(ValueTask))
            {
                await next(context);
                return;
            }
            var returnType = methodReturnType;
            if (isAsync)
            {
                returnType = returnType.GenericTypeArguments.FirstOrDefault();
            }
            //string param = GetParaName(context.Parameters); //获取方法的参数名,
            string key = $"Methods:{context.ImplementationMethod.DeclaringType.FullName}.{context.ImplementationMethod.Name}";//获取方法名称,也就是缓存key值
            var cache = context.ServiceProvider.GetService<MemoryCache>(); //可以使用自定义的redis或者其他缓存
            if (cache.Get(key) != null)
            {
                //反射获取缓存值
                var value = typeof(MemoryCache).GetMethod("MemoryCache.Get").MakeGenericMethod(returnType).Invoke(cache, new[] {
                    key
                    //, param 
                });
                if (isAsync)
                {

                    //判断是Task还是ValueTask
                    if (methodReturnType == typeof(Task<>).MakeGenericType(returnType))
                    {
                        //反射获取Task<>类型的返回值,相当于Task.FromResult(value)
                        context.ReturnValue = typeof(Task).GetMethod(nameof(Task.FromResult)).MakeGenericMethod(returnType).Invoke(null, new[] { value });
                    }
                    else if (methodReturnType == typeof(ValueTask<>).MakeGenericType(returnType))
                    {
                        //反射构建ValueTask<>类型的返回值,相当于new ValueTask(value)
                        context.ReturnValue = Activator.CreateInstance(typeof(ValueTask<>).MakeGenericType(returnType), value);
                    }
                }
                else
                {
                    context.ReturnValue = value;
                }
                return;
            }
            await next(context);
            object returnValue;
            if (isAsync)
            {
                returnValue = await context.UnwrapAsyncReturnValue();
                //反射获取异步结果的值,相当于(context.ReturnValue as Task<>).Result
                //returnValue = typeof(Task<>).MakeGenericType(returnType).GetProperty(nameof(Task<object>.Result)).GetValue(context.ReturnValue);

            }
            else
            {
                returnValue = context.ReturnValue;
            }
            cache.Set(key
                //, param
                , returnValue);
            if(ExpireSeconds > 0)
            {
                cache.Set(key, TimeSpan.FromSeconds(ExpireSeconds));//设置key的过期时间
            }
        }

        //private string GetParaName(object[] parameters)
        //{
        //    throw new NotImplementedException();
        //}

        /// <summary>
        /// 缓存秒数
        /// </summary>
        public int ExpireSeconds { get; set; }
    }
复制代码

dbcontext的代理

复制代码
public class TransactionInterceptorAttribute : AbstractInterceptorAttribute
    {
        //public override async Task Invoke(AspectContext context, AspectDelegate next)
        //{
        //    var dbcontext = context.ServiceProvider.GetService<CommonDbContext>();
        //    if (dbcontext.Database.CurrentTransaction != null)
        //    {
        //        await dbcontext.Database.BeginTransactionAsync();
        //        try
        //        {
        //            await next(context);
        //            await dbcontext.Database.CommitTransactionAsync();
        //        }catch(Exception ex)
        //        {
        //           await dbcontext.Database.RollbackTransactionAsync();
        //            throw ex;
        //        }
        //    }
        //    else
        //    {
        //        await next(context);
        //    }
        //}//一个context

        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            var dbcontext = context.ServiceProvider.GetService<CommonDbContext>();
            var dbcontextNext = context.ServiceProvider.GetService<NextDbContext>();
            var transactionManager = dbcontext.Database.GetService<IDbContextTransactionManager>();
            var transaction = await transactionManager.BeginTransactionAsync();

            if (transaction != null)
            {
                await dbcontext.Database.BeginTransactionAsync();
                try
                {
                    await next(context);
                    await transaction.CommitAsync();
                }
                catch (Exception ex)
                {
                    await transaction.RollbackAsync();
                    throw ex;
                }
            }
            else
            {
                await next(context);
            }
        }//多个context
    }
复制代码 复制代码
 public class CommonDbContext:DbContext
    {
        public CommonDbContext(DbContextOptions<CommonDbContext> options):base(options)
        {

        }
    }

    public class NextDbContext : DbContext
    {
        public NextDbContext(DbContextOptions<CommonDbContext> options) : base(options)
        {

        }
    }
复制代码

使用就是这么简单

复制代码
 public class TestOperatorDbBusiness
    {
        [TransactionInterceptor]
        public async ValueTask Add()
        {
            //TODO事务操作
        }
    }
复制代码

 

上面的代理组件功能非常多,项目中需要自己去研究更多更全的用法。

上面代码的demo

exercisebook/AOP at main · liuzhixin405/exercisebook (github.com)

还有Castle.DynamicProxy,这个比较复杂一点。具体用法给个实例demo

exercisebook/AspNetCoreAOP at main · liuzhixin405/exercisebook (github.com)

总结:

一个aspnetcore中需要用到aop的地方非常多,框架自带的中间件,filter过滤器,efcore自带Interceptor都可以拿来用。

中间件例如mediator,这里面的拦截器也非常多,还有好多等待发掘。

当然自己也可以定义一些简单的中间层来做拦截。

相信多了解 在框架中有需要用的地方会事半功倍。

 

 

出处:https://www.cnblogs.com/morec/p/17249940.html

标签:Task,方式,aspnetcore,await,next,context,AOP,var,public
From: https://www.cnblogs.com/mq0036/p/17250893.html

相关文章

  • java -jar 启动设置参数的三种方式
    java-jar参数前后位置说明springboot项目启动的时候可以直接使用java-jarxxx.jar这样。下面说说参数的一些讲究1.-DpropName=propValue的形式携带,要放在-jar参数前面(......
  • Mac M2 colima qemu apline 中的使用9p 挂载方式查看
    挂载方式默认使用sshfs存在权限问题因此改为9p查看挂载的目录自动在macOS上挂载$HOME目录在macooscolimasshmount|grepUsers具体含义mount0on/Us......
  • aspnetcore中aop的实现
    aaspnetcore开发框架中实现aop不仅仅在业务上,在代码的优雅简洁和架构的稳定上都有着至关重要。下面介绍三种用过的。 第一种通过System.Reflection的DispatchProxy类来......
  • 第二章:3、数据传输方式脑图
    ......
  • SG90舵机的原理和控制方式
    前言做过机器人、智能车或者玩航模的朋友应该对舵机不会陌生,这种舵机也是很常用的。舵机只是我们通俗的叫法,它的本质是一个伺服电机,也可以叫做位置(角度)伺服驱动器。一般被......
  • 打开CMD的方式 使用MaKDown学习
    打开CMD的方式1.开始+系统+命令提示符2.Win+R输入cmd打开控制台3.在任意文件夹下面,按住shift键+鼠标右键点击,在此处打开命令行窗口4.资源管理器的地址前面加上cmd路劲......
  • Spring依赖注入的方式
    ①变量注入:注入方式简单简洁,没有多余代码。但可能会导致循环依赖。②构造器注入:避免循环依赖。但注入过多会导致代码臃肿。③setter方法注入:注入的依赖可以为NULL。使用......
  • 常用命令行连接方式
    以下控制端均以windows为例1.linux下(包含Android等嵌入式linux)1.1adb调试adb是基于usb或以太网wifi等局域网之上的工具,在被控端嵌入式linux端有个监听adbd进程,控......
  • Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理?
    好啦,开始今天的正文。大家都知道,AOP底层是动态代理,而Java中的动态代理有两种实现方式:基于JDK的动态代理基于Cglib的动态代理这两者最大的区别在于基于JDK的......
  • 婚恋感情中常见的PUA方式
    1.打压你的婚恋价值,从长相,条件,性格等角度打压你,让你认为自己存在明显缺陷。有车有房,就说对你没感觉,你家境不错,就说你工作不想,什么都不错就说你身高不行,总能找到你的缺点。......