拦截异步方法,返回一般任务<>通过DynamicProxy [英] Intercept async method that returns generic Task<> via DynamicProxy

查看:124
本文介绍了拦截异步方法,返回一般任务<>通过DynamicProxy的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题与本文相关拦截呼叫一个使用DynamicProxy的异步方法

我想实现一个拦截器,它可以处理返回任务的异步方法,或任务< T> 结果。

I want to implement interceptor that works with async methods that returns Task or Task<T> result.

我使用下面的代码返回 ContinueWith result(为了在拦截器完成工作时调用方法等待) p>

I use next code for return ContinueWith result (in order that caller method wait while interceptor finishes work)

var task = invocation.ReturnValue as Task;
invocation.ReturnValue = task.ContinueWith(c => 
      { code that should execute after method finish });

以上代码适用于任务结果,但如果任务< T> 结果 ContinueWith 会将返回类型从任务< T> ; 任务
我需要调用重载的方法ContinueWith返回 Task< T> ,但为此我需要转换 invocation.ReturnValue 任务< T>

Above code works fine for Task result, but in case of Task<T> result ContinueWith will change return type from Task<T> to Task. I need to call overloaded method ContinueWith that returns Task<T>, but for this I need to cast invocation.ReturnValue to Task<T>

我没有办法以任何方式动态地投射它。
有人知道如何做到这一点吗?

I didn't find way to cast it dynamically in any way. Does anyone know how to make it?

我也尝试通过反射调用此方法,但参数是labmda函数,无法直接传递。

I also tried to call this method via reflection, but parameter is labmda function that can't be passed directly.

推荐答案

经过广泛的研究,我能够创建一个解决方案,用于拦截同步方法以及异步任务和异步任务; TResult>。

After extensive research, I was able to create a solution that works for intercepting Synchronous Methods as well as Async Task and Async Task< TResult >.

这是我使用Castle Dynamic Proxy在异常处理拦截器上运行的所有方法类型的代码。这种模式适合做任何你想要的拦截。对于标准的BeforeInvoke / AfterInvoke操作,语法会稍微干净些,但概念应该是相同的。

Here is my code for an Exception Handling interceptor that works on all those method types, using Castle Dynamic Proxy. This pattern is adaptable for doing any sort of intercept you wish. The syntax will be a little cleaner for standard BeforeInvoke/AfterInvoke actions, but the concept should be the same.

(其他注意:示例中的IExceptionHandler接口是自定义类型,而不是普通对象。)

(Other note: the IExceptionHandler interface in the example is a custom type, and not a common object.)

    private class AsyncExceptionHandlingInterceptor : IInterceptor
    {
        private static readonly MethodInfo handleAsyncMethodInfo = typeof(AsyncExceptionHandlingInterceptor).GetMethod("HandleAsyncWithResult", BindingFlags.Instance | BindingFlags.NonPublic);
        private readonly IExceptionHandler _handler;

        public AsyncExceptionHandlingInterceptor(IExceptionHandler handler)
        {
            _handler = handler;
        }

        public void Intercept(IInvocation invocation)
        {
            var delegateType = GetDelegateType(invocation);
            if (delegateType == MethodType.Synchronous)
            {
                _handler.HandleExceptions(() => invocation.Proceed());
            }
            if (delegateType == MethodType.AsyncAction)
            {
                invocation.Proceed();
                invocation.ReturnValue = HandleAsync((Task)invocation.ReturnValue);
            }
            if (delegateType == MethodType.AsyncFunction)
            {
                invocation.Proceed();
                ExecuteHandleAsyncWithResultUsingReflection(invocation);
            }
        }

        private void ExecuteHandleAsyncWithResultUsingReflection(IInvocation invocation)
        {
            var resultType = invocation.Method.ReturnType.GetGenericArguments()[0];
            var mi = handleAsyncMethodInfo.MakeGenericMethod(resultType);
            invocation.ReturnValue = mi.Invoke(this, new[] { invocation.ReturnValue });
        }

        private async Task HandleAsync(Task task)
        {
            await _handler.HandleExceptions(async () => await task);
        }

        private async Task<T> HandleAsyncWithResult<T>(Task<T> task)
        {
            return await _handler.HandleExceptions(async () => await task);
        }

        private MethodType GetDelegateType(IInvocation invocation)
        {
            var returnType = invocation.Method.ReturnType;
            if (returnType == typeof(Task))
                return MethodType.AsyncAction;
            if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
                return MethodType.AsyncFunction;
            return MethodType.Synchronous;
        }

        private enum MethodType
        {
            Synchronous,
            AsyncAction,
            AsyncFunction
        }
    }

这篇关于拦截异步方法,返回一般任务&lt;&gt;通过DynamicProxy的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆