@@ -22,8 +22,9 @@ public abstract class AsyncInterceptorBase : IAsyncInterceptor
2222#endif
2323
2424 private static readonly MethodInfo InterceptSynchronousMethodInfo =
25- typeof ( AsyncInterceptorBase )
26- . GetMethod ( nameof ( InterceptSynchronousResult ) , BindingFlags . Static | BindingFlags . NonPublic ) ;
25+ typeof ( AsyncInterceptorBase ) . GetMethod (
26+ nameof ( InterceptSynchronousResult ) ,
27+ BindingFlags . Static | BindingFlags . NonPublic ) ;
2728
2829 private static readonly ConcurrentDictionary < Type , GenericSynchronousHandler > GenericSynchronousHandlers =
2930 new ConcurrentDictionary < Type , GenericSynchronousHandler >
@@ -50,7 +51,7 @@ void IAsyncInterceptor.InterceptSynchronous(IInvocation invocation)
5051 /// <param name="invocation">The method invocation.</param>
5152 void IAsyncInterceptor . InterceptAsynchronous ( IInvocation invocation )
5253 {
53- invocation . ReturnValue = InterceptAsync ( invocation , ProceedAsynchronous ) ;
54+ invocation . ReturnValue = InterceptAsync ( invocation . GetProceedInfo ( ) , ProceedAsynchronous ) ;
5455 }
5556
5657 /// <summary>
@@ -60,27 +61,29 @@ void IAsyncInterceptor.InterceptAsynchronous(IInvocation invocation)
6061 /// <param name="invocation">The method invocation.</param>
6162 void IAsyncInterceptor . InterceptAsynchronous < TResult > ( IInvocation invocation )
6263 {
63- invocation . ReturnValue = InterceptAsync ( invocation , ProceedAsynchronous < TResult > ) ;
64+ invocation . ReturnValue = InterceptAsync ( invocation . GetProceedInfo ( ) , ProceedAsynchronous < TResult > ) ;
6465 }
6566
6667 /// <summary>
6768 /// Override in derived classes to intercept method invocations.
6869 /// </summary>
69- /// <param name="invocation ">The method invocation .</param>
70- /// <param name="proceed">The function to proceed the <paramref name="invocation "/>.</param>
70+ /// <param name="proceedInfo ">The <see cref="IInvocationProceedInfo"/> .</param>
71+ /// <param name="proceed">The function to proceed the <paramref name="proceedInfo "/>.</param>
7172 /// <returns>A <see cref="Task" /> object that represents the asynchronous operation.</returns>
72- protected abstract Task InterceptAsync ( IInvocation invocation , Func < IInvocation , Task > proceed ) ;
73+ protected abstract Task InterceptAsync (
74+ IInvocationProceedInfo proceedInfo ,
75+ Func < IInvocationProceedInfo , Task > proceed ) ;
7376
7477 /// <summary>
7578 /// Override in derived classes to intercept method invocations.
7679 /// </summary>
7780 /// <typeparam name="TResult">The type of the <see cref="Task{T}"/> <see cref="Task{T}.Result"/>.</typeparam>
78- /// <param name="invocation ">The method invocation .</param>
79- /// <param name="proceed">The function to proceed the <paramref name="invocation "/>.</param>
81+ /// <param name="proceedInfo ">The <see cref="IInvocationProceedInfo"/> .</param>
82+ /// <param name="proceed">The function to proceed the <paramref name="proceedInfo "/>.</param>
8083 /// <returns>A <see cref="Task" /> object that represents the asynchronous operation.</returns>
8184 protected abstract Task < TResult > InterceptAsync < TResult > (
82- IInvocation invocation ,
83- Func < IInvocation , Task < TResult > > proceed ) ;
85+ IInvocationProceedInfo proceedInfo ,
86+ Func < IInvocationProceedInfo , Task < TResult > > proceed ) ;
8487
8588 private static GenericSynchronousHandler CreateHandler ( Type returnType )
8689 {
@@ -90,12 +93,15 @@ private static GenericSynchronousHandler CreateHandler(Type returnType)
9093
9194 private static void InterceptSynchronousVoid ( AsyncInterceptorBase me , IInvocation invocation )
9295 {
93- Task task = me . InterceptAsync ( invocation , ProceedSynchronous ) ;
96+ Task task = me . InterceptAsync ( invocation . GetProceedInfo ( ) , ProceedSynchronous ) ;
9497
9598 // If the intercept task has yet to complete, wait for it.
9699 if ( ! task . IsCompleted )
97100 {
98- Task . Run ( ( ) => task ) . Wait ( ) ;
101+ // Need to use Task.Run() to prevent deadlock in .NET Framework ASP.NET requests.
102+ // GetAwaiter().GetResult() prevents a thrown exception being wrapped in a AggregateException.
103+ // See https://stackoverflow.com/a/17284612
104+ Task . Run ( ( ) => task ) . GetAwaiter ( ) . GetResult ( ) ;
99105 }
100106
101107 if ( task . IsFaulted )
@@ -106,12 +112,15 @@ private static void InterceptSynchronousVoid(AsyncInterceptorBase me, IInvocatio
106112
107113 private static void InterceptSynchronousResult < TResult > ( AsyncInterceptorBase me , IInvocation invocation )
108114 {
109- Task task = me . InterceptAsync ( invocation , ProceedSynchronous < TResult > ) ;
115+ Task < TResult > task = me . InterceptAsync ( invocation . GetProceedInfo ( ) , ProceedSynchronous < TResult > ) ;
110116
111117 // If the intercept task has yet to complete, wait for it.
112118 if ( ! task . IsCompleted )
113119 {
114- Task . Run ( ( ) => task ) . Wait ( ) ;
120+ // Need to use Task.Run() to prevent deadlock in .NET Framework ASP.NET requests.
121+ // GetAwaiter().GetResult() prevents a thrown exception being wrapped in a AggregateException.
122+ // See https://stackoverflow.com/a/17284612
123+ Task . Run ( ( ) => task ) . GetAwaiter ( ) . GetResult ( ) ;
115124 }
116125
117126 if ( task . IsFaulted )
@@ -120,11 +129,11 @@ private static void InterceptSynchronousResult<TResult>(AsyncInterceptorBase me,
120129 }
121130 }
122131
123- private static Task ProceedSynchronous ( IInvocation invocation )
132+ private static Task ProceedSynchronous ( IInvocationProceedInfo proceedInfo )
124133 {
125134 try
126135 {
127- invocation . Proceed ( ) ;
136+ proceedInfo . Invoke ( ) ;
128137#if NETSTANDARD2_0
129138 return Task . CompletedTask ;
130139#else
@@ -143,12 +152,12 @@ private static Task ProceedSynchronous(IInvocation invocation)
143152 }
144153 }
145154
146- private static Task < TResult > ProceedSynchronous < TResult > ( IInvocation invocation )
155+ private static Task < TResult > ProceedSynchronous < TResult > ( IInvocationProceedInfo proceedInfo )
147156 {
148157 try
149158 {
150- invocation . Proceed ( ) ;
151- return Task . FromResult ( ( TResult ) invocation . ReturnValue ) ;
159+ proceedInfo . Invoke ( ) ;
160+ return Task . FromResult ( ( TResult ) proceedInfo . Invocation . ReturnValue ) ;
152161 }
153162 catch ( Exception e )
154163 {
@@ -162,22 +171,22 @@ private static Task<TResult> ProceedSynchronous<TResult>(IInvocation invocation)
162171 }
163172 }
164173
165- private static async Task ProceedAsynchronous ( IInvocation invocation )
174+ private static async Task ProceedAsynchronous ( IInvocationProceedInfo proceedInfo )
166175 {
167- invocation . Proceed ( ) ;
176+ proceedInfo . Invoke ( ) ;
168177
169178 // Get the task to await.
170- var originalReturnValue = ( Task ) invocation . ReturnValue ;
179+ var originalReturnValue = ( Task ) proceedInfo . Invocation . ReturnValue ;
171180
172181 await originalReturnValue . ConfigureAwait ( false ) ;
173182 }
174183
175- private static async Task < TResult > ProceedAsynchronous < TResult > ( IInvocation invocation )
184+ private static async Task < TResult > ProceedAsynchronous < TResult > ( IInvocationProceedInfo proceedInfo )
176185 {
177- invocation . Proceed ( ) ;
186+ proceedInfo . Invoke ( ) ;
178187
179188 // Get the task to await.
180- var originalReturnValue = ( Task < TResult > ) invocation . ReturnValue ;
189+ var originalReturnValue = ( Task < TResult > ) proceedInfo . Invocation . ReturnValue ;
181190
182191 TResult result = await originalReturnValue . ConfigureAwait ( false ) ;
183192 return result ;
0 commit comments