Skip to content

Commit

Permalink
First hack using the updates for Castle.Core
Browse files Browse the repository at this point in the history
  • Loading branch information
JSkimming committed Mar 25, 2019
1 parent e315aff commit 96d9a0f
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 41 deletions.
61 changes: 35 additions & 26 deletions src/Castle.Core.AsyncInterceptor/AsyncInterceptorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ public abstract class AsyncInterceptorBase : IAsyncInterceptor
#endif

private static readonly MethodInfo InterceptSynchronousMethodInfo =
typeof(AsyncInterceptorBase)
.GetMethod(nameof(InterceptSynchronousResult), BindingFlags.Static | BindingFlags.NonPublic);
typeof(AsyncInterceptorBase).GetMethod(
nameof(InterceptSynchronousResult),
BindingFlags.Static | BindingFlags.NonPublic);

private static readonly ConcurrentDictionary<Type, GenericSynchronousHandler> GenericSynchronousHandlers =
new ConcurrentDictionary<Type, GenericSynchronousHandler>
Expand All @@ -50,7 +51,7 @@ void IAsyncInterceptor.InterceptSynchronous(IInvocation invocation)
/// <param name="invocation">The method invocation.</param>
void IAsyncInterceptor.InterceptAsynchronous(IInvocation invocation)
{
invocation.ReturnValue = InterceptAsync(invocation, ProceedAsynchronous);
invocation.ReturnValue = InterceptAsync(invocation.GetProceedInfo(), ProceedAsynchronous);
}

/// <summary>
Expand All @@ -60,27 +61,29 @@ void IAsyncInterceptor.InterceptAsynchronous(IInvocation invocation)
/// <param name="invocation">The method invocation.</param>
void IAsyncInterceptor.InterceptAsynchronous<TResult>(IInvocation invocation)
{
invocation.ReturnValue = InterceptAsync(invocation, ProceedAsynchronous<TResult>);
invocation.ReturnValue = InterceptAsync(invocation.GetProceedInfo(), ProceedAsynchronous<TResult>);
}

/// <summary>
/// Override in derived classes to intercept method invocations.
/// </summary>
/// <param name="invocation">The method invocation.</param>
/// <param name="proceed">The function to proceed the <paramref name="invocation"/>.</param>
/// <param name="proceedInfo">The <see cref="IInvocationProceedInfo"/>.</param>
/// <param name="proceed">The function to proceed the <paramref name="proceedInfo"/>.</param>
/// <returns>A <see cref="Task" /> object that represents the asynchronous operation.</returns>
protected abstract Task InterceptAsync(IInvocation invocation, Func<IInvocation, Task> proceed);
protected abstract Task InterceptAsync(
IInvocationProceedInfo proceedInfo,
Func<IInvocationProceedInfo, Task> proceed);

/// <summary>
/// Override in derived classes to intercept method invocations.
/// </summary>
/// <typeparam name="TResult">The type of the <see cref="Task{T}"/> <see cref="Task{T}.Result"/>.</typeparam>
/// <param name="invocation">The method invocation.</param>
/// <param name="proceed">The function to proceed the <paramref name="invocation"/>.</param>
/// <param name="proceedInfo">The <see cref="IInvocationProceedInfo"/>.</param>
/// <param name="proceed">The function to proceed the <paramref name="proceedInfo"/>.</param>
/// <returns>A <see cref="Task" /> object that represents the asynchronous operation.</returns>
protected abstract Task<TResult> InterceptAsync<TResult>(
IInvocation invocation,
Func<IInvocation, Task<TResult>> proceed);
IInvocationProceedInfo proceedInfo,
Func<IInvocationProceedInfo, Task<TResult>> proceed);

private static GenericSynchronousHandler CreateHandler(Type returnType)
{
Expand All @@ -90,12 +93,15 @@ private static GenericSynchronousHandler CreateHandler(Type returnType)

private static void InterceptSynchronousVoid(AsyncInterceptorBase me, IInvocation invocation)
{
Task task = me.InterceptAsync(invocation, ProceedSynchronous);
Task task = me.InterceptAsync(invocation.GetProceedInfo(), ProceedSynchronous);

// If the intercept task has yet to complete, wait for it.
if (!task.IsCompleted)
{
Task.Run(() => task).Wait();
// Need to use Task.Run() to prevent deadlock in .NET Framework ASP.NET requests.
// GetAwaiter().GetResult() prevents a thrown exception being wrapped in a AggregateException.
// See https://stackoverflow.com/a/17284612
Task.Run(() => task).GetAwaiter().GetResult();
}

if (task.IsFaulted)
Expand All @@ -106,12 +112,15 @@ private static void InterceptSynchronousVoid(AsyncInterceptorBase me, IInvocatio

private static void InterceptSynchronousResult<TResult>(AsyncInterceptorBase me, IInvocation invocation)
{
Task task = me.InterceptAsync(invocation, ProceedSynchronous<TResult>);
Task<TResult> task = me.InterceptAsync(invocation.GetProceedInfo(), ProceedSynchronous<TResult>);

// If the intercept task has yet to complete, wait for it.
if (!task.IsCompleted)
{
Task.Run(() => task).Wait();
// Need to use Task.Run() to prevent deadlock in .NET Framework ASP.NET requests.
// GetAwaiter().GetResult() prevents a thrown exception being wrapped in a AggregateException.
// See https://stackoverflow.com/a/17284612
Task.Run(() => task).GetAwaiter().GetResult();
}

if (task.IsFaulted)
Expand All @@ -120,11 +129,11 @@ private static void InterceptSynchronousResult<TResult>(AsyncInterceptorBase me,
}
}

private static Task ProceedSynchronous(IInvocation invocation)
private static Task ProceedSynchronous(IInvocationProceedInfo proceedInfo)
{
try
{
invocation.Proceed();
proceedInfo.Invoke();
#if NETSTANDARD2_0
return Task.CompletedTask;
#else
Expand All @@ -143,12 +152,12 @@ private static Task ProceedSynchronous(IInvocation invocation)
}
}

private static Task<TResult> ProceedSynchronous<TResult>(IInvocation invocation)
private static Task<TResult> ProceedSynchronous<TResult>(IInvocationProceedInfo proceedInfo)
{
try
{
invocation.Proceed();
return Task.FromResult((TResult)invocation.ReturnValue);
proceedInfo.Invoke();
return Task.FromResult((TResult)proceedInfo.Invocation.ReturnValue);
}
catch (Exception e)
{
Expand All @@ -162,22 +171,22 @@ private static Task<TResult> ProceedSynchronous<TResult>(IInvocation invocation)
}
}

private static async Task ProceedAsynchronous(IInvocation invocation)
private static async Task ProceedAsynchronous(IInvocationProceedInfo proceedInfo)
{
invocation.Proceed();
proceedInfo.Invoke();

// Get the task to await.
var originalReturnValue = (Task)invocation.ReturnValue;
var originalReturnValue = (Task)proceedInfo.Invocation.ReturnValue;

await originalReturnValue.ConfigureAwait(false);
}

private static async Task<TResult> ProceedAsynchronous<TResult>(IInvocation invocation)
private static async Task<TResult> ProceedAsynchronous<TResult>(IInvocationProceedInfo proceedInfo)
{
invocation.Proceed();
proceedInfo.Invoke();

// Get the task to await.
var originalReturnValue = (Task<TResult>)invocation.ReturnValue;
var originalReturnValue = (Task<TResult>)proceedInfo.Invocation.ReturnValue;

TResult result = await originalReturnValue.ConfigureAwait(false);
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,14 +280,16 @@ public class WhenExceptionInterceptingAnAsynchronousMethodThatThrowsASynchronous
{
private class MyInterceptorBase : AsyncInterceptorBase
{
protected override Task InterceptAsync(IInvocation invocation, Func<IInvocation, Task> proceed)
protected override Task InterceptAsync(IInvocationProceedInfo proceedInfo, Func<IInvocationProceedInfo, Task> proceed)
{
return proceed(invocation);
return proceed(proceedInfo);
}

protected override Task<TResult> InterceptAsync<TResult>(IInvocation invocation, Func<IInvocation, Task<TResult>> proceed)
protected override Task<TResult> InterceptAsync<TResult>(
IInvocationProceedInfo proceedInfo,
Func<IInvocationProceedInfo, Task<TResult>> proceed)
{
return proceed(invocation);
return proceed(proceedInfo);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,46 @@ public TestAsyncInterceptorBase(ListLogger log, int msDeley)
_msDeley = msDeley;
}

protected override async Task InterceptAsync(IInvocation invocation, Func<IInvocation, Task> proceed)
protected override async Task InterceptAsync(IInvocationProceedInfo proceedInfo, Func<IInvocationProceedInfo, Task> proceed)
{
try
{
_log.Add($"{invocation.Method.Name}:StartingVoidInvocation");
_log.Add($"{proceedInfo.Invocation.Method.Name}:StartingVoidInvocation");

await Task.Yield();
await proceed(invocation).ConfigureAwait(false);
await proceed(proceedInfo).ConfigureAwait(false);

if (_msDeley > 0)
await Task.Delay(_msDeley).ConfigureAwait(false);

_log.Add($"{invocation.Method.Name}:CompletedVoidInvocation");
_log.Add($"{proceedInfo.Invocation.Method.Name}:CompletedVoidInvocation");
}
catch (Exception e)
{
_log.Add($"{invocation.Method.Name}:VoidExceptionThrown:{e.Message}");
_log.Add($"{proceedInfo.Invocation.Method.Name}:VoidExceptionThrown:{e.Message}");
throw;
}
}

protected override async Task<TResult> InterceptAsync<TResult>(
IInvocation invocation,
Func<IInvocation, Task<TResult>> proceed)
IInvocationProceedInfo proceedInfo,
Func<IInvocationProceedInfo, Task<TResult>> proceed)
{
try
{
_log.Add($"{invocation.Method.Name}:StartingResultInvocation");
_log.Add($"{proceedInfo.Invocation.Method.Name}:StartingResultInvocation");

TResult result = await proceed(invocation).ConfigureAwait(false);
TResult result = await proceed(proceedInfo).ConfigureAwait(false);

if (_msDeley > 0)
await Task.Delay(_msDeley).ConfigureAwait(false);

_log.Add($"{invocation.Method.Name}:CompletedResultInvocation");
_log.Add($"{proceedInfo.Invocation.Method.Name}:CompletedResultInvocation");
return result;
}
catch (Exception e)
{
_log.Add($"{invocation.Method.Name}:ResultExceptionThrown:{e.Message}");
_log.Add($"{proceedInfo.Invocation.Method.Name}:ResultExceptionThrown:{e.Message}");
throw;
}
}
Expand Down

0 comments on commit 96d9a0f

Please sign in to comment.