拦截返回通用任务的异步方法通过动态代理 [英] Intercept async method that returns generic Task<> via DynamicProxy
问题描述
我的问题与这篇文章有关 拦截对使用 DynamicProxy 的异步方法
My questions is related to this post Intercept the call to an async method using DynamicProxy
我想实现与返回 Task
或 Task
结果的异步方法一起使用的拦截器.
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屋!