aspnetcore中aop的实现
阅读原文时间:2023年07月08日阅读:5

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<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(); //可以使用自定义的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();
// 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 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,这里面的拦截器也非常多,还有好多等待发掘。

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

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