Browse Source

Merge pull request #969 from abpframework/castle-async-interceptors

Implement fully async interceptors
pull/975/head
Halil İbrahim Kalkan 8 years ago
committed by GitHub
parent
commit
4bd011939e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs
  2. 6
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs
  3. 62
      framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs
  4. 6
      framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs
  5. 2
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/CachedTestObject.cs
  6. 2
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleAsyncInterceptor.cs

2
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs

@ -35,7 +35,7 @@ namespace Volo.Abp.Authorization
return; return;
} }
AsyncHelper.RunSync(() => AuthorizeAsync(invocation)); await AuthorizeAsync(invocation);
await invocation.ProceedAsync(); await invocation.ProceedAsync();
} }

6
framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs

@ -30,7 +30,7 @@ namespace Volo.Abp.Caching
protected ICurrentTenant CurrentTenant { get; } protected ICurrentTenant CurrentTenant { get; }
//protected AsyncLock AsyncLock { get; } = new AsyncLock(); protected AsyncLock AsyncLock { get; } = new AsyncLock();
protected DistributedCacheEntryOptions DefaultCacheOptions; protected DistributedCacheEntryOptions DefaultCacheOptions;
@ -135,7 +135,7 @@ namespace Volo.Abp.Caching
return value; return value;
} }
//using (AsyncLock.Lock(CancellationTokenProvider.Token)) using (AsyncLock.Lock(CancellationTokenProvider.Token))
{ {
value = Get(key, hideErrors); value = Get(key, hideErrors);
if (value != null) if (value != null)
@ -164,7 +164,7 @@ namespace Volo.Abp.Caching
return value; return value;
} }
//using (await AsyncLock.LockAsync(token)) using (await AsyncLock.LockAsync(token))
{ {
value = await GetAsync(key, hideErrors, token); value = await GetAsync(key, hideErrors, token);
if (value != null) if (value != null)

62
framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs

@ -1,4 +1,5 @@
using System.Threading.Tasks; using System.Reflection;
using System.Threading.Tasks;
using Castle.DynamicProxy; using Castle.DynamicProxy;
using Volo.Abp.DynamicProxy; using Volo.Abp.DynamicProxy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
@ -8,6 +9,20 @@ namespace Volo.Abp.Castle.DynamicProxy
public class CastleAbpInterceptorAdapter<TInterceptor> : IInterceptor public class CastleAbpInterceptorAdapter<TInterceptor> : IInterceptor
where TInterceptor : IAbpInterceptor where TInterceptor : IAbpInterceptor
{ {
private static readonly MethodInfo MethodExecuteWithoutReturnValueAsync =
typeof(CastleAbpInterceptorAdapter<TInterceptor>)
.GetMethod(
nameof(ExecuteWithoutReturnValueAsync),
BindingFlags.NonPublic | BindingFlags.Instance
);
private static readonly MethodInfo MethodExecuteWithReturnValueAsync =
typeof(CastleAbpInterceptorAdapter<TInterceptor>)
.GetMethod(
nameof(ExecuteWithReturnValueAsync),
BindingFlags.NonPublic | BindingFlags.Instance
);
private readonly TInterceptor _abpInterceptor; private readonly TInterceptor _abpInterceptor;
public CastleAbpInterceptorAdapter(TInterceptor abpInterceptor) public CastleAbpInterceptorAdapter(TInterceptor abpInterceptor)
@ -17,39 +32,58 @@ namespace Volo.Abp.Castle.DynamicProxy
public void Intercept(IInvocation invocation) public void Intercept(IInvocation invocation)
{ {
var proceedInfo = invocation.CaptureProceedInfo();
var method = invocation.MethodInvocationTarget ?? invocation.Method; var method = invocation.MethodInvocationTarget ?? invocation.Method;
if (method.IsAsync()) if (method.IsAsync())
{ {
InterceptAsyncMethod(invocation); InterceptAsyncMethod(invocation, proceedInfo);
} }
else else
{ {
InterceptSyncMethod(invocation); InterceptSyncMethod(invocation, proceedInfo);
} }
} }
private void InterceptAsyncMethod(IInvocation invocation) private void InterceptSyncMethod(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{
_abpInterceptor.Intercept(new CastleAbpMethodInvocationAdapter(invocation, proceedInfo));
}
private void InterceptAsyncMethod(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{ {
if (invocation.Method.ReturnType == typeof(Task)) if (invocation.Method.ReturnType == typeof(Task))
{ {
invocation.ReturnValue = _abpInterceptor.InterceptAsync(new CastleAbpMethodInvocationAdapter(invocation)); invocation.ReturnValue = MethodExecuteWithoutReturnValueAsync
.Invoke(this, new object[] { invocation, proceedInfo });
} }
else else
{ {
var interceptResult = _abpInterceptor.InterceptAsync(new CastleAbpMethodInvocationAdapter(invocation)); invocation.ReturnValue = MethodExecuteWithReturnValueAsync
var actualReturnValue = invocation.ReturnValue; .MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0])
invocation.ReturnValue = InternalAsyncHelper.CallAwaitTaskWithPreActionAndPostActionAndFinallyAndGetResult( .Invoke(this, new object[] {invocation, proceedInfo});
invocation.Method.ReturnType.GenericTypeArguments[0],
() => actualReturnValue,
() => interceptResult
);
} }
} }
private void InterceptSyncMethod(IInvocation invocation) private async Task ExecuteWithoutReturnValueAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{ {
_abpInterceptor.Intercept(new CastleAbpMethodInvocationAdapter(invocation)); await Task.Yield();
await _abpInterceptor.InterceptAsync(
new CastleAbpMethodInvocationAdapter(invocation, proceedInfo)
);
}
private async Task<T> ExecuteWithReturnValueAsync<T>(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{
await Task.Yield();
await _abpInterceptor.InterceptAsync(
new CastleAbpMethodInvocationAdapter(invocation, proceedInfo)
);
return await (Task<T>)invocation.ReturnValue;
} }
} }
} }

6
framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs

@ -32,10 +32,10 @@ namespace Volo.Abp.Castle.DynamicProxy
protected IInvocation Invocation { get; } protected IInvocation Invocation { get; }
protected IInvocationProceedInfo ProceedInfo { get; } protected IInvocationProceedInfo ProceedInfo { get; }
public CastleAbpMethodInvocationAdapter(IInvocation invocation) public CastleAbpMethodInvocationAdapter(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{ {
Invocation = invocation; Invocation = invocation;
ProceedInfo = invocation.CaptureProceedInfo(); ProceedInfo = proceedInfo;
_lazyArgumentsDictionary = new Lazy<IReadOnlyDictionary<string, object>>(GetArgumentsDictionary); _lazyArgumentsDictionary = new Lazy<IReadOnlyDictionary<string, object>>(GetArgumentsDictionary);
} }
@ -53,7 +53,9 @@ namespace Volo.Abp.Castle.DynamicProxy
public Task ProceedAsync() public Task ProceedAsync()
{ {
ProceedInfo.Invoke(); ProceedInfo.Invoke();
_actualReturnValue = Invocation.ReturnValue; _actualReturnValue = Invocation.ReturnValue;
return Invocation.Method.IsAsync() return Invocation.Method.IsAsync()
? (Task)_actualReturnValue ? (Task)_actualReturnValue
: Task.FromResult(_actualReturnValue); : Task.FromResult(_actualReturnValue);

2
framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/CachedTestObject.cs

@ -1,3 +1,4 @@
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Volo.Abp.DynamicProxy namespace Volo.Abp.DynamicProxy
@ -6,6 +7,7 @@ namespace Volo.Abp.DynamicProxy
{ {
public virtual int GetValue(int v) public virtual int GetValue(int v)
{ {
Thread.Sleep(5);
return v; return v;
} }

2
framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleAsyncInterceptor.cs

@ -14,7 +14,7 @@ namespace Volo.Abp.DynamicProxy
public override async Task InterceptAsync(IAbpMethodInvocation invocation) public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{ {
//await Task.Delay(5); CAN NOT USE await before method execution! This is a restriction of Castle DynamicProxy await Task.Delay(5);
(invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_InterceptAsync_BeforeInvocation"); (invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_InterceptAsync_BeforeInvocation");
await invocation.ProceedAsync(); await invocation.ProceedAsync();
(invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_InterceptAsync_AfterInvocation"); (invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_InterceptAsync_AfterInvocation");

Loading…
Cancel
Save