使用 DynamicProxy 拦截对异步方法的调用 [英] Intercept the call to an async method using DynamicProxy

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

问题描述

下面是实现 Castle 动态代理 库.此代码段来自基于 AOP 的日志概念验证控制台应用程序,该应用程序已发布此处.

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 an AOP based logging proof-of-concept console app that is posted here.

    public void Intercept(IInvocation invocation)
    {
        if (Log.IsDebugEnabled) Log.Debug(CreateInvocationLogString("Called", invocation));
        try
        {
            invocation.Proceed();
            if (Log.IsDebugEnabled)
                if (invocation.Method.ReturnType != typeof(void))
                    Log.Debug("Returning with: " + invocation.ReturnValue);
        }
        catch (Exception ex)
        {
            if (Log.IsErrorEnabled) Log.Error(CreateInvocationLogString("ERROR", invocation), ex);
            throw;
        }
    }

这在常规方法调用上按预期工作,但在使用 async 方法(使用 C# 5.0 中的 async/await 关键字)时则不然.我相信,我也理解这背后的原因.

This is working as expected on regular method calls, but not when tried with async methods (using the async/await keywords from C# 5.0). And I believe, I understand the reasons behind this as well.

为了使async/await工作,编译器将方法的函数体添加到幕后的状态机中,控制权将返回给调用者,只要第一个awaitable 表达式.

For the async/await to work, the compiler adds the functional body of the method into a state machine behind the scenes and the control will return to the caller, as soon as the first awaitable expression that cannot be completed synchronously, is encountered.

此外,我们可以查询返回类型并确定我们是否正在处理这样的 async 方法:

Also, we can interrogate the return type and figure out whether we are dealing with an async method like this:

            if (invocation.Method.ReturnType == typeof(Task) || 
                (invocation.Method.ReturnType.IsGenericType && 
                 invocation.Method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)))
                Log.Info("Asynchronous method found...");

这仅适用于返回 TaskTask<> 而不是 void 的那些 async 方法但我觉得没问题.

This works for only those async methods that returns either Task or Task<> and not void but I am fine with that.

必须在 Intercept 方法中进行哪些更改,以便 awaiter 返回到那里而不是原始调用者?

What changes have to made within the Intercept method so that the awaiter would return to there rather than the original caller?

推荐答案

大概问题"在于它只是记录它正在返回一个任务——而你想要该任务中的 ?

Presumably the "problem" is that it's just logging that it's returning a task - and you want the value within that task?

假设是这种情况,您仍然必须立即将任务返回给调用者 - 无需等待它完成.如果你打破它,你从根本上把事情搞砸了.

Assuming that's the case, you still have to return the task to the caller, immediately - without waiting for it to complete. If you break that, you're fundamentally messing things up.

但是,在将任务返回给调用者之前,您应该添加一个延续(通过 Task.ContinueWith) 将在任务完成时记录结果(或失败).这仍然会提供结果信息,但当然您可能会在其他一些日志记录之后记录它.您可能想在返回之前立即登录,导致日志如下:

However, before you return the task to the caller, you should add a continuation (via Task.ContinueWith) which will log the result (or failure) when the task completes. That will still give the result information, but of course you'll be logging it potentially after some other logging. You may also want to log immediately before returning, leading to a log something like this:

Called FooAsync
Returned from FooAsync with a task
Task from FooAsync completed, with return value 5

从任务中获取结果的业务(如果它成功完成)必须通过反射来完成,这有点痛苦 - 或者您可以使用动态类型.(无论哪种方式都会影响性能.)

The business of getting the result out of the task (if it completed successfully) would have to be done with reflection, which is a bit of a pain - or you could use dynamic typing. (Either way it will be a bit of a performance hit.)

这篇关于使用 DynamicProxy 拦截对异步方法的调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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