拦截返回通用任务的异步方法通过动态代理 [英] Intercept async method that returns generic Task<> via DynamicProxy

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

问题描述

我的问题与这篇文章有关 拦截对使用 DynamicProxy 的异步方法

My questions is related to this post Intercept the call to an async method using DynamicProxy

我想实现与返回 TaskTask 结果的异步方法一起使用的拦截器.

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

我使用下一个代码返回 ContinueWith 结果(以便调用方方法在拦截器完成工作时等待)

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 });

以上代码适用于 Task 结果,但在 Task 结果的情况下 ContinueWith 将从 更改返回类型任务Task.我需要调用返回 Task 的重载方法 ContinueWith,但为此我需要将 invocation.ReturnValue 转换为 Task

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.

推荐答案

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

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 动态代理.这种模式适用于执行您希望的任何类型的拦截.对于标准的 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
        }
    }

这篇关于拦截返回通用任务的异步方法通过动态代理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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