aspnetcore中aop的实现

2023-03-24 06:19:46 来源: 博客园

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

下面介绍三种用过的。


(资料图片)

第一种通过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.Create(warService);        }        public string WipeOut()        {            return "us is over";        }    }

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

public class WarDispatch : DispatchProxy where T : class    {        private T Target { get; set; }        public static T Create(T target) where T : class        {            var proxy = Create>() as WarDispatch;            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();

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

下面简单介绍下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();            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(); //可以使用自定义的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.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();        //}        ///         /// 缓存秒数        ///         public int ExpireSeconds { get; set; }    }

dbcontext的代理

public class TransactionInterceptorAttribute : AbstractInterceptorAttribute    {        //public override async Task Invoke(AspectContext context, AspectDelegate next)        //{        //    var dbcontext = context.ServiceProvider.GetService();        //    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();            var dbcontextNext = context.ServiceProvider.GetService();            var transactionManager = dbcontext.Database.GetService();            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 options):base(options)        {        }    }    public class NextDbContext : DbContext    {        public NextDbContext(DbContextOptions 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,这里面的拦截器也非常多,还有好多等待发掘。

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

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

标签:

[责任编辑:]

最近更新