C# 拦截返回通用任务的异步方法<&燃气轮机;通过DynamicProxy

C# 拦截返回通用任务的异步方法<&燃气轮机;通过DynamicProxy,c#,generics,async-await,castle-dynamicproxy,C#,Generics,Async Await,Castle Dynamicproxy,我的问题与这篇文章有关 我想实现一个拦截器,它与返回Task或Task结果的异步方法一起工作 我使用下一个代码返回ContinueWithresult(以便调用方方法在拦截器完成工作时等待) 上述代码适用于任务结果,但在任务结果的情况下继续将返回类型从任务更改为任务。 我需要调用重载的ContinueWith方法,该方法返回Task,但为此我需要将invocation.ReturnValue转换为Task 我没有找到任何方法来动态地投射它。 有人知道怎么做吗 我还尝试通过反射调用此方法,但参数是

我的问题与这篇文章有关

我想实现一个拦截器,它与返回
Task
Task
结果的异步方法一起工作

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

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

我没有找到任何方法来动态地投射它。 有人知道怎么做吗


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

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

下面是我使用Castle动态代理处理所有这些方法类型的异常处理拦截器的代码。此模式适用于执行任何类型的拦截。对于标准的BeforeInvoke/AfterInvoke操作,语法会稍微清晰一些,但概念应该是相同的

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

私有类AsyncExceptionHandlingInterceptor:IInterceptor
{
私有静态只读方法info handleAsyncMethodInfo=typeof(AsyncExceptionHandlingInterceptor).GetMethod(“HandleAsyncWithResult”,BindingFlags.Instance | BindingFlags.NonPublic);
私有只读IEExceptionHandler\u处理程序;
公共AsyncExceptionHandlingInterceptor(IEExceptionHandler)
{
_handler=handler;
}
公共无效拦截(IInvocation调用)
{
var delegateType=GetDelegateType(调用);
if(delegateType==MethodType.Synchronous)
{
_HandleExceptions(()=>invocation.procedure());
}
if(delegateType==MethodType.AsyncAction)
{
invocation.procedure();
invocation.ReturnValue=HandleAsync((任务)invocation.ReturnValue);
}
if(delegateType==MethodType.AsyncFunction)
{
invocation.procedure();
ExecuteHandleAsyncWithResultUsingReflection(调用);
}
}
私有void ExecuteHandleAsyncWithResultUsingReflection(IInvocation调用)
{
var resultType=invocation.Method.ReturnType.GetGenericArguments()[0];
var mi=handleAsyncMethodInfo.MakeGenericMethod(结果类型);
invocation.ReturnValue=mi.Invoke(这是新的[]{invocation.ReturnValue});
}
专用异步任务HandleAsync(任务任务)
{
wait _handler.HandleExceptions(异步()=>wait任务);
}
专用异步任务HandleAsyncWithResult(任务任务)
{
返回wait _handler.HandleExceptions(异步()=>wait任务);
}
私有MethodType GetDelegateType(IInvocation调用)
{
var returnType=invocation.Method.returnType;
if(returnType==typeof(任务))
返回MethodType.AsyncAction;
if(returnType.IsGenericType&&returnType.GetGenericTypeDefinition()==typeof(任务))
返回MethodType.async函数;
返回MethodType.Synchronous;
}
私有枚举方法类型
{
同步的
异步操作,
异步函数
}
}

更好的解决方案是使用
dynamic
关键字绕过编译器类型检查,并在运行时解析操作:

public void Intercept(IInvocation invocation)
{
    invocation.Proceed();
    var method = invocation.MethodInvocationTarget;
    var isAsync = method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null;
    if (isAsync && typeof(Task).IsAssignableFrom(method.ReturnType))
    {
        invocation.ReturnValue = InterceptAsync((dynamic)invocation.ReturnValue);
    }
}

private static async Task InterceptAsync(Task task)
{
    await task.ConfigureAwait(false);
    // do the continuation work for Task...
}

private static async Task<T> InterceptAsync<T>(Task<T> task)
{
    T result = await task.ConfigureAwait(false);
    // do the continuation work for Task<T>...
    return result;
}
公共无效截获(IInvocation调用)
{
invocation.procedure();
var method=invocation.MethodInvocationTarget;
var isAsync=method.GetCustomAttribute(typeof(AsyncStateMachineAttribute))!=null;
if(isAsync&&typeof(Task).IsAssignableFrom(method.ReturnType))
{
invocation.ReturnValue=InterceptAsync((动态)invocation.ReturnValue);
}
}
专用静态异步任务侦听异步(任务任务)
{
等待任务。配置等待(false);
//做任务的延续工作。。。
}
专用静态异步任务侦听异步(任务任务)
{
T结果=等待任务。配置等待(false);
//做任务的延续工作。。。
返回结果;
}

由于需要拦截返回任务的方法,我创建了对
Castle.Core
的扩展,简化了过程

该软件包可在上下载

该解决方案主要基于的答案,但通过提供一个新的接口来实现,从而简化了它。还有进一步的抽象,使拦截类似于实现
拦截器

有关更多详细信息,请参见项目说明。

我是这样做的:

invocation.Proceed(); 
object response;
Type type = invocation.ReturnValue?.GetType();
if (type != null && typeof(Task).IsAssignableFrom(type))
{
    var resultProperty = type.GetProperty("Result");
    response = resultProperty.GetValue(invocation.ReturnValue);
}

@Silas Reinagel和@thepirat000的解决方案对我不起作用,我使用@James skiming的
Castle.Core.AsyncInterceptor
解决方案也没有成功

在我的例子中,我截获了一个返回
任务的异步方法,只有在
调用.procedue()过程中没有异常时,它才应该“在调用后.procedue()code”执行。最后,我使用了@jamesskiming,因此此解决方案仅适用于拦截返回
Task
的异步方法,而不是
Task

公共无效截获(IInvocation调用)
{
_stepPriorInvocation();
invocation.procedure();
Func continuation=async()=>
{
等待(任务)
public void Intercept(IInvocation invocation)
{
    invocation.Proceed();
    var method = invocation.MethodInvocationTarget;
    var isAsync = method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null;
    if (isAsync && typeof(Task).IsAssignableFrom(method.ReturnType))
    {
        invocation.ReturnValue = InterceptAsync((dynamic)invocation.ReturnValue);
    }
}

private static async Task InterceptAsync(Task task)
{
    await task.ConfigureAwait(false);
    // do the continuation work for Task...
}

private static async Task<T> InterceptAsync<T>(Task<T> task)
{
    T result = await task.ConfigureAwait(false);
    // do the continuation work for Task<T>...
    return result;
}
invocation.Proceed(); 
object response;
Type type = invocation.ReturnValue?.GetType();
if (type != null && typeof(Task).IsAssignableFrom(type))
{
    var resultProperty = type.GetProperty("Result");
    response = resultProperty.GetValue(invocation.ReturnValue);
}