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<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包

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

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

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

aspnetcore中aop的实现的更多相关文章

  1. AspNetCore 基于AOP实现Polly的使用

    前言   说起AOP,其实我们在做MVC/API 的时候应该没少接触,比如说各种的Fitter 就是典型的AOP了. 本来在使用Polly的时候我最初的打算是使用过滤器来实现的,后来发现实现起来相当的 ...

  2. Spring中AOP原理,源码学习笔记

    一.AOP(面向切面编程):通过预编译和运行期动态代理的方式在不改变代码的情况下给程序动态的添加一些功能.利用AOP可以对应用程序的各个部分进行隔离,在Spring中AOP主要用来分离业务逻辑和系统级 ...

  3. Spring中AOP简介与切面编程的使用

    Spring中AOP简介与使用 什么是AOP? Aspect Oriented Programming(AOP),多译作 "面向切面编程",也就是说,对一段程序,从侧面插入,进行操 ...

  4. 在AspNetCore 中 使用Redis实现分布式缓存

    AspNetCore 使用Redis实现分布式缓存 上一篇讲到了,Core的内置缓存:IMemoryCache,以及缓存的基础概念.本篇会进行一些概念上的补充. 本篇我们记录的内容是怎么在Core中使 ...

  5. AspNetCore中使用Ocelot之 IdentityServer4(1)

    AspNetCore中使用Ocelot之 IdentityServer4(1) 前言: OceLot网关是基于AspNetCore 产生的可扩展的高性能的企业级Api网关,目前已经基于2.0 升级版本 ...

  6. 第四节:MVC中AOP思想的体现(四种过滤器)并结合项目案例说明过滤器的实际用法

    一. 简介 MVC中的过滤器可以说是MVC框架中的一种灵魂所在,它是MVC框架中AOP思想的具体体现,所以它以面向切面的形式无侵入式的作用于代码的业务逻辑,与业务逻辑代码分离,一经推出,广受开发者的喜 ...

  7. 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)

    一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...

  8. Spring中AOP实现

    1.什么是SpringAOP 什么是aop:Aspect Oriented Programming的缩写,面向切面编程,通过预编译和动态代理实现程序功能的 统一维护的一种技术 主要功能:日志记录,性能 ...

  9. Spring 中aop切面注解实现

    spring中aop的注解实现方式简单实例   上篇中我们讲到spring的xml实现,这里我们讲讲使用注解如何实现aop呢.前面已经讲过aop的简单理解了,这里就不在赘述了. 注解方式实现aop我们 ...

  10. 在ASPNETCORE中获得所有Action

    在ASPNETCORE中获得所有Action 本文旨在记录自己在aspnetcore工作中需要获取所有Action,在查询了资料后进行了几种方法的记录.后期有发现其它方式再进行追加. 一.通过 反射 ...

随机推荐

  1. 20192305 王梓全Python程序设计实验四报告

    20192305 王梓全Python程序设计实验四报告 课程:<Python程序设计> 班级: 1923 姓名: 王梓全 学号:20192305 实验教师:王志强 实验日期:2021年6月 ...

  2. 第08组Beta冲刺(3/4)

    队名 八组评分了吗 组长博客链接(2分) 组员1李昕晖(组长) 过去两天完成了哪些任务 文字/口头描述 了解各个小组的进度与难以攻破的地方,晚上安排开会,安排新的冲刺任务. 重新分配小组及个人任务. ...

  3. tensorflow疑问总结

    1.sigmoid 函数为什么不好? (1)激活函数计算量大(在正向传播和反向传播中都包含幂运算和除法) (2)反向传播求误差梯度时,求导涉及除法 (3)Sigmoid倒数取值范围是[0,0.25], ...

  4. HTTP协议中的长连接和短链接

    一.概念 HTTP长连接,也称持久连接,是使用同一个TCP连接来发送和接受多个HTTP请求/应答,而不是位每一个新的请求/应答打开新的TCP连接.这种方式由于通信连接一直存在,此种方式常用于P2P通信 ...

  5. Markdown基础使用学习

    Mark Down学习 标题:#+标题名字 二级标题:## +标题名字 三级... 字体 两个*+字+两个=加粗 一个=斜体 引用 一个大于号+内容 图片 ![图片名字](路径) 符号全部小写 超链接 ...

  6. vue中使用Echart将一组数据展示出三种统计图

    1 <template> 2 <div class="container"> 3 <div id="myEchart" style ...

  7. 通过【leaflet】 调用高德离线瓦片地图

    官网:https://leafletjs.com/ 首先在官网下载[leaflet.css]和[leaflet.js] 引用js和css <link href="js/leaflet. ...

  8. jmeter设置支持https方法

    2020-2-26,疫情影响下第一天上班,今年想把自己学到的测试方面的知识记录下来,方便自己方便有需要的人,废话不多说,开启第一篇随笔,jmeter设置. 最近在测接口性能,涉及https的接口,不知 ...

  9. ssh问题、原理及diffie hellman算法

    1.普通用户无法使用证书登录:原因是权限设置问题 将.ssh目录设为700,authorized_keys设为600即可. 2.查看ssh支持的算法 ssh -Q help ssh -Q kex/ke ...

  10. supper网盘快速下载器

    本人搬砖党喜欢和大家分享一些快速文档 废话少说 很好用,亲测.对有需求的人 速度很快 软件永久有效下载链接:链接: https://pan.baidu.com/s/1g6LIk4mw18Bov0U7D ...