我正在开始一个新项目,我正在考虑使用简单的注入器拦截(https://simpleinjector.readthedocs.io/en/latest/InterceptionExtensions.html)来跟踪方法进入/退出和记录参数和返回值等。我过去用过这个拦截器,效果很好。但我之前的项目不是async/await。这个新项目有很多方法都是async/await的,我想知道
- 这个拦截器将为async/await方法工作吗?
- 在这个拦截器需要什么变化,使其工作为异步/等待方法?
我知道decorator是一种比拦截更好的模式,但是为我想要跟踪的每个接口编写decorator并不是我想要做的事情。
更新:我已经在我的async/await代码中尝试了这个拦截器,它确实注入了我的跟踪代码。然而,我在应用程序的某些部分得到了奇怪的结果。我没有机会深入挖掘为什么禁用拦截会使它工作得很好,为什么当启用拦截时它不会像预期的那样工作。很可能是我的代码出了问题。
我希望如果有人,谁已经使用这个拦截扩展在他们的代码,将能够指出我在正确的方向。
c#中的Async代码是这个拦截器会为async/await方法工作吗?
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));
}
}