async/await代码中简单的注入器拦截



我正在开始一个新项目,我正在考虑使用简单的注入器拦截(https://simpleinjector.readthedocs.io/en/latest/InterceptionExtensions.html)来跟踪方法进入/退出和记录参数和返回值等。我过去用过这个拦截器,效果很好。但我之前的项目不是async/await。这个新项目有很多方法都是async/await的,我想知道

  • 这个拦截器将为async/await方法工作吗?
  • 在这个拦截器需要什么变化,使其工作为异步/等待方法?

我知道decorator是一种比拦截更好的模式,但是为我想要跟踪的每个接口编写decorator并不是我想要做的事情。

更新:我已经在我的async/await代码中尝试了这个拦截器,它确实注入了我的跟踪代码。然而,我在应用程序的某些部分得到了奇怪的结果。我没有机会深入挖掘为什么禁用拦截会使它工作得很好,为什么当启用拦截时它不会像预期的那样工作。很可能是我的代码出了问题。

我希望如果有人,谁已经使用这个拦截扩展在他们的代码,将能够指出我在正确的方向。

这个拦截器会为async/await方法工作吗?

c#中的Async代码是Task之上的语法糖。这意味着,如果你的代码需要在调用异步方法之后做任何有用的,你将在返回的Task上调用ContinueWith(或使用c#语法)。如果你在你的拦截器中考虑异步,你将无法在包装对象之后执行逻辑。

所以要使这个工作,你必须明确检查包装的方法是否返回Task,如果是这种情况,你应该通过使用ContinueWith挂钩你的"后"代码来使事情异步。

这是我认为拦截不如使用装饰器的众多原因之一。装饰器让你的代码更干净,避免使用反射,提供完整的编译时支持,提供更好的性能,避免不得不依赖拦截库,并迫使你进入一个更坚实的应用程序设计。

也就是说,当考虑异步性时,文档的MonitoringInterceptor看起来如下:

class MonitoringInterceptor : IInterceptor
{
    private readonly ILogger logger;
    public MonitoringInterceptor(ILogger logger) {
        this.logger = logger;
    }
    public void Intercept(IInvocation invocation) {
        var watch = Stopwatch.StartNew();
        // Calls the decorated instance.
        invocation.Proceed();
        var task = invocation.ReturnValue as Task;
        if (task != null) {
            invocation.ReturnValue = LogElapsedAsync(task, invocation, watch);
        } else {
            LogElapsed(invocation, watch);
        }
    }
    private async Task LogElapsedAsync(Task task, IInvocation i, Stopwatch w) {
        await task;
        LogElapsed(i, w);
    }
    private void LogElapsed(IInvocation invocation, Stopwatch watch) {
        var decoratedType = invocation.InvocationTarget.GetType();
        this.logger.Log(string.Format("{0} executed in {1} ms.",
            decoratedType.Name, watch.ElapsedMilliseconds));
    }
}

最新更新