Intercept the call to an async method using DynamicProxy

后端 未结 8 1003
隐瞒了意图╮
隐瞒了意图╮ 2020-12-13 02:30

Below is the code from the Intercept method on a custom type that implements IInterceptor of the Castle Dynamic Proxy library. This snippet is from

8条回答
  •  天涯浪人
    2020-12-13 02:54

    Below is my async interceptor adapter implementation that correctly handles async methods.

    abstract class AsyncInterceptor : IInterceptor
    {
        class TaskCompletionSourceMethodMarkerAttribute : Attribute
        {
    
        }
    
        private static readonly MethodInfo _taskCompletionSourceMethod = typeof(AsyncInterceptor)
            .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
            .Single(x => x.GetCustomAttributes(typeof(TaskCompletionSourceMethodMarkerAttribute)).Any());
    
    
        protected virtual Task InterceptAsync(Object target, MethodBase method, object[] arguments, Func> proceed)
        {
            return proceed();
        }
    
        protected virtual void Intercept(Object target, MethodBase method, object[] arguments, Action proceed)
        {
            proceed();
        }
    
        [TaskCompletionSourceMethodMarker]
        Task TaskCompletionSource(IInvocation invocation)
        {
            var tcs = new TaskCompletionSource();
    
            var task = InterceptAsync(invocation.InvocationTarget, invocation.Method, invocation.Arguments, () =>
            {
                var task2 = (Task)invocation.Method.Invoke(invocation.InvocationTarget, invocation.Arguments);
                var tcs2 = new TaskCompletionSource();
                task2.ContinueWith(x =>
                {
                    if (x.IsFaulted)
                    {
                        tcs2.SetException(x.Exception);
                        return;
                    }
                    dynamic dynamicTask = task2;
                    Object result = dynamicTask.Result;
                    tcs2.SetResult(result);
                });
                return tcs2.Task;
            });
    
            task.ContinueWith(x =>
            {
                if (x.IsFaulted)
                {
                    tcs.SetException(x.Exception);
                    return;
                }
    
                tcs.SetResult((TResult)x.Result);
            });
    
            return tcs.Task;
        }
        void IInterceptor.Intercept(IInvocation invocation)
        {
            if (!typeof(Task).IsAssignableFrom(invocation.Method.ReturnType))
            {
                Intercept(invocation.InvocationTarget, invocation.Method, invocation.Arguments, invocation.Proceed);
                return;
            }
            var returnType = invocation.Method.ReturnType.IsGenericType ? invocation.Method.ReturnType.GetGenericArguments()[0] : typeof(object);
            var method = _taskCompletionSourceMethod.MakeGenericMethod(returnType);
            invocation.ReturnValue = method.Invoke(this, new object[] { invocation });
        }
    }
    
    
    

    and sample usage:

    class TestInterceptor : AsyncInterceptor
    {
        protected override async Task InterceptAsync(object target, MethodBase method, object[] arguments, Func> proceed)
        {
            await Task.Delay(5000);
            var result = await proceed();
            return DateTime.Now.Ticks % 2 == 0 ? 10000 :result;
        }
    }
    
        

    提交回复
    热议问题