5

aspnetcore中aop的实现 - 星仔007

 1 year ago
source link: https://www.cnblogs.com/morec/p/17249940.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

aspnetcore中aop的实现

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

下面介绍三种用过的。

第一种通过System.Reflection的DispatchProxy类来实现

首先新建一个aspnetcore项目

1099890-20230323225909848-1069554898.png

针对业务代码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>();

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

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

首先引用aspnetcore.extensions.dependencyinjection包

1099890-20230323231248237-1691420192.png

在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,这里面的拦截器也非常多,还有好多等待发掘。

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK