背景
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: Vicent 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);
}
}
//didn't support ValueTask yet
protected virtual bool IsAsyncMethod(MethodInfo method)
{
bool isDefAsync = Attribute.IsDefined(method, typeof(AsyncStateMachineAttribute), false);
bool isAsync = isDefAsync && typeof(Task).IsAssignableFrom(method.ReturnType);
return isAsync;
}
private async Task InterceptAsync(Task task, IInvocation invocation)
{
await task.ConfigureAwait(false);
await AfterProceedAsync(invocation, false);
}
protected object ProceedAsyncResult { get; set; }
private async Task<TResult> InterceptAsync<TResult>(Task<TResult> task, IInvocation invocation)
{
TResult result = await task.ConfigureAwait(false);
ProceedAsyncResult = result;
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;
}
}
}
對於異步攔截器的其他實現方法,可參考此代碼樣例。