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 ) { 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 } 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(DbContextOptionsoptions):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,这里面的拦截器也非常多,还有好多等待发掘。
当然自己也可以定义一些简单的中间层来做拦截。
相信多了解 在框架中有需要用的地方会事半功倍。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.e1idc.net