Cal*_*ton 1 c# autofac interception async-await
所以我有这门课:
public class MappingBootstrap : IMappingBootstrap
{
public virtual async Task Map()
{
// Order is very important
await this.mapper1.Map();
await this.mapper2.Map();
await this.mapper3.Map();
await this.mapper4.Map();
}
}
Run Code Online (Sandbox Code Playgroud)
我有Autofac拦截器:
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var methodReference = Guid.NewGuid();
Console.WriteLine($"Calling {invocation?.Method?.DeclaringType?.Name}.{invocation?.Method?.Name} : {methodReference}");
var startNew = Stopwatch.StartNew();
invocation?.Proceed();
startNew.Stop();
Console.WriteLine($"{methodReference} : Done, time taken: {startNew.ElapsedMilliseconds}ms");
}
}
Run Code Online (Sandbox Code Playgroud)
这会产生输出:
调用IMapperBootstrap.Map:54425559-71fe-4f23-ab47-d0f3371ec819
调用IMapper1.Map:51babb34-fa83-42ed-84e7-a1e979528116
51babb34-fa83-42ed-84e7-a1e979528116:完成,所用时间:219ms
54425559-71fe-4f23- ab47-d0f3371ec819:完成,所用时间:221ms
呼叫IMapper2.Map:41c812a2-d82d-48f6-9b8d-139b52eb28e3
41c812a2-d82d-48f6-9b8d-139b52eb28e3:完成,所用时间:9ms
呼叫IMapper3.Map:c91bed04-8f86-47d3 -a35a-417e354c2c5f
c91bed04-8f86-47d3-a35a-417e354c2c5f:完成,所需时间:994ms
调用IMapper4.Map:035cad27-1ba8-4bd1-b85f-396f64998d97
035cad27-1ba8-4bd1-b85f-396f64998d97:完成,所用时间:18ms
正如您所看到的,MappingBoostrap.Map完成后的第一个Mapper1.Map而不是我期望的所有功能完成后的结束.为什么?
Autofac配置:
builder.Register(context => new LoggingInterceptor());
builder
.RegisterAssemblyTypes(typeof(Bootstrapper).Assembly)
.Where(x => x.Namespace.Contains("Mapping"))
.AsImplementedInterfaces()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(LoggingInterceptor));
Run Code Online (Sandbox Code Playgroud)
为什么?
当您调用这样的异步方法时:
mapping.Map();
Run Code Online (Sandbox Code Playgroud)
它只启动方法.这就是异步方法的工作方式(正如我在博客中解释的那样).如果await异步方法返回任务,则当前方法将暂停,直到异步方法完成:
await mapping.Map();
Run Code Online (Sandbox Code Playgroud)
在拦截的情况下,理想的解决方案是使Proceed和Intercept方法异步:
public async Task InterceptAsync(IInvocation invocation)
{
...
await invocation?.ProceedAsync();
...
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,Autofac没有内置的异步方法理解,所以这是不可能的.相反,你必须调用Proceed,它只是启动异步方法.异步方法返回一个Task,表示该方法的执行.要挂钩完成该方法,您应该用Task自己的方法替换它.
对于一个简单的Task返回方法,你可以使用这样的东西:
public void Intercept(IInvocation invocation)
{
var methodReference = Guid.NewGuid();
Console.WriteLine($"Calling {invocation?.Method?.DeclaringType?.Name}.{invocation?.Method?.Name} : {methodReference}");
var startNew = Stopwatch.StartNew();
invocation.Proceed();
invocation.ReturnValue = WatchAsync(methodReference, startNew, (Task)invocation.ReturnValue);
}
private static async Task WatchAsync(Guid methodReference,
Stopwatch stopwatch, Task methodExecution)
{
try
{
await methodExecution.ConfigureAwait(false);
}
finally
{
stopwatch.Stop();
Console.WriteLine($"{methodReference} : Done, time taken: {stopwatch.ElapsedMilliseconds}ms");
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1578 次 |
| 最近记录: |