.Net Core AOP 使用 Autofac 异步拦截器
背景 autofac使用拦截器实现AOP,是基于Castle.Core的.然而Castle.Core并未提供原生异步支持.所以需要使用帮助类实现,这在autofac官方文档的已知问题中有详细说明。 对于该问题的讨论,最早出现于stackoverflow James Skimming基于其中的一个答案,研发了一个帮助包即: Castle.Core.AsyncInterceptor 我之前也一直使用的是该方案,不过thepirat000随后提出了一个使用dynamic的更加简化的实现方法 我对该方法进行了一些封装,实现了一个帮助包,大家可以尝试一下。 项目地址: https://github.com/wswind/lightwind 使用 使用时,你可以通过nuget安装Lightwind.Asyncinterceptor也可以直接拷贝AsyncInterceptorBase.cs放入你的项目中。样例代码可点击这里查看 其核心代码是封装实现一个支持异步处理的Interceptor父类,让开发者能够继承实现自己的拦截器。开发时,仅需关注所拦截的方法,在执行前后该添加什么处理逻辑. 异步拦截器的执行流程如下: 在所拦截的方法执行前,首先执行BeforeProceed,方法执行后,如果为同步方法,则后续执行AfterProceedSync 如果为异步方法,则await所拦截的方法使其真正执行后,调用AfterProceedAsync进行异步方法的后续处理。 对于异步执行且有返回值的情况,可通过hasAsynResult参数判断是否有返回值,通过ProceedAsynResult属性读取或修改所拦截方法的最终返回值. 代码的运行流程图如下: AsyncInterceptorBase.cs实现如下: // Licence: MIT // Author: Vincent Wang // Email: ws_dev@163.com // ProjectUrl: https://github.com/wswind/lightwind using System; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading.Tasks; using Castle.DynamicProxy; namespace Lightwind.AsyncInterceptor { //inspired by : https://stackoverflow.com/a/39784559/7726468 public abstract class AsyncInterceptorBase : IInterceptor { public AsyncInterceptorBase() { } public void Intercept(IInvocation invocation) { BeforeProceed(invocation); invocation.Proceed(); if (IsAsyncMethod(invocation.MethodInvocationTarget)) { // 关键实现语句 invocation.ReturnValue = InterceptAsync((dynamic)invocation.ReturnValue, invocation); } else { AfterProceedSync(invocation); } } private bool CheckMethodReturnTypeIsTaskType(MethodInfo method) { var methodReturnType = method.ReturnType; if(methodReturnType.IsGenericType) { if (methodReturnType.GetGenericTypeDefinition() == typeof(Task<>) || methodReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>)) return true; } else { if (methodReturnType == typeof(Task) || methodReturnType == typeof(ValueTask)) return true; } return false; } private bool IsAsyncMethod(MethodInfo method) { bool isDefAsync = Attribute.IsDefined(method, typeof(AsyncStateMachineAttribute), false); bool isTaskType = CheckMethodReturnTypeIsTaskType(method); bool isAsync = isDefAsync && isTaskType; return isAsync; } protected object ProceedAsyncResult { get; set; } private async Task InterceptAsync(Task task, IInvocation invocation) { await task.ConfigureAwait(false); await AfterProceedAsync(invocation, false); } private async Task<TResult> InterceptAsync<TResult>(Task<TResult> task, IInvocation invocation) { ProceedAsyncResult = await task.ConfigureAwait(false); await AfterProceedAsync(invocation, true); return (TResult)ProceedAsyncResult; } private async ValueTask InterceptAsync(ValueTask task, IInvocation invocation) { await task.ConfigureAwait(false); await AfterProceedAsync(invocation, false); } private async ValueTask<TResult> InterceptAsync<TResult>(ValueTask<TResult> task, IInvocation invocation) { ProceedAsyncResult = await task.ConfigureAwait(false); await AfterProceedAsync(invocation, true); return (TResult)ProceedAsyncResult; } protected virtual void BeforeProceed(IInvocation invocation) { } protected virtual void AfterProceedSync(IInvocation invocation) { } protected virtual Task AfterProceedAsync(IInvocation invocation, bool hasAsynResult) { return Task.CompletedTask; } } } 上述代码的关键实现语句为InterceptAsync((dynamic)invocation.ReturnValue, invocation),C#会在运行时依据invocation.ReturnValue的类型调用正确的重载函数,即:InterceptAsync / InterceptAsync<TResult> ...