c# - 使用 DynamicProxy 拦截对异步方法的调用

标签 c# reflection aop async-await castle-dynamicproxy

下面是来自 Intercept 的代码实现 IInterceptor 的自定义类型上的方法的 Castle Dynamic Proxy图书馆。此片段来自 AOP发布的基于日志记录的概念验证控制台应用程序 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 关键字)。我相信,我也理解这背后的原因。

对于 async/await为了工作,编译器将方法的功能体添加到幕后的状态机中,一旦第一个 awaitable 出现,控制权将返回给调用者。遇到无法同步完成的表达式。

此外,我们可以查询返回类型并弄清楚我们是否正在处理 async。像这样的方法:

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

这只适用于那些 async返回 Task 的方法或 Task<>而不是 void但我对此没有意见。

必须在 Intercept 中进行哪些更改?方法使得 awaiter会回到那里而不是原来的来电者?

最佳答案

大概“问题”是它只是记录它正在返回一个任务 - 而您想要该任务中的

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

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

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

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

关于c# - 使用 DynamicProxy 拦截对异步方法的调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14288075/

相关文章:

java - 按名称检索注释

java方法返回类型不是实际类型

c# - AOP Postsharp,记录变量值

c# - 如何获取给定字符的 ASCII 码?

c# - 指定的转换在 C# 中无效

c# - 文本框可见属性

structuremap - 您可以使用结构图将依赖项注入(inject) postsharp 属性吗

c# - 在动态列数上连接 2 个数据表

c# - 有没有一种类型化的方法来在 C# 中声明方法名称

java - Spring AOP : Aspect not working on called method