Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Autofac拦截异步执行顺序_C#_Async Await_Autofac_Interception - Fatal编程技术网

C# Autofac拦截异步执行顺序

C# Autofac拦截异步执行顺序,c#,async-await,autofac,interception,C#,Async Await,Autofac,Interception,所以我有一节课: 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();

所以我有一节课:

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();
    }
}
我有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");
    }
}
这将产生以下输出:

调用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:完成,所用时间:9毫秒
调用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:完成,所用时间:18毫秒

正如您所看到的,
MappingBoostrap.Map
在第一个
Mapper1.Map
之后完成,而不是在我预期的所有函数完成时完成为什么?


自动传真配置:

builder.Register(context => new LoggingInterceptor());

builder
    .RegisterAssemblyTypes(typeof(Bootstrapper).Assembly)
    .Where(x => x.Namespace.Contains("Mapping"))
    .AsImplementedInterfaces()
    .EnableInterfaceInterceptors()
    .InterceptedBy(typeof(LoggingInterceptor));
为什么?

当您调用如下异步方法时:

mapping.Map();
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");
  }
}
它只会启动该方法。这是(正如我在博客上解释的)。如果您等待异步方法返回的任务,则当前方法将暂停,直到异步方法完成:

await mapping.Map();
在拦截的情况下,理想的解决方案是让
继续
拦截
方法异步:

public async Task InterceptAsync(IInvocation invocation)
{
  ...
  await invocation?.ProceedAsync();
  ...
}
不幸的是,Autofac对异步方法没有内置的理解,因此这是不可能的。相反,您必须调用
继续
,这只是启动异步方法。异步方法返回一个
任务
,它表示该方法的执行。为了完成该方法,您应该用自己的任务替换该任务

对于普通的
任务
-返回方法,可以使用如下内容:

mapping.Map();
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");
  }
}
为什么?

当您调用如下异步方法时:

mapping.Map();
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");
  }
}
它只会启动该方法。这是(正如我在博客上解释的)。如果您等待异步方法返回的任务,则当前方法将暂停,直到异步方法完成:

await mapping.Map();
在拦截的情况下,理想的解决方案是让
继续
拦截
方法异步:

public async Task InterceptAsync(IInvocation invocation)
{
  ...
  await invocation?.ProceedAsync();
  ...
}
不幸的是,Autofac对异步方法没有内置的理解,因此这是不可能的。相反,您必须调用
继续
,这只是启动异步方法。异步方法返回一个
任务
,它表示该方法的执行。为了完成该方法,您应该用自己的任务替换该任务

对于普通的
任务
-返回方法,可以使用如下内容:

mapping.Map();
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");
  }
}

我想知道这是否是原因,但我有一部分人说为什么Autofac不支持
wait/async
,但这似乎是一个简单的解决方案。问题是您希望拦截处理如何等待
任务
s,还是处理实际调用发生的代码。我想这是在截取异步代码时必须记住的事情之一。@Callumlington:要清楚,被截取的代码仍然应该使用
await
。截取代码只是截取返回的
任务
,并将其替换为自己的任务(这恰好是通过
异步
/
等待
实现的)。请注意,截取是由Castle.DynamicProxy而不是Autofac完成的。Autofac只是让连接更容易。正如FYI@StephenCleary一样,调用
WatchAsync
方法时使用的参数数量不正确Sam I correct如果调用返回的任务有参数,此方法将失败?如果是这样的话,如果我们不想为每个可能调用的方法编写代码,我们该怎么办?我想知道这是否是原因,但我的某些部分说,为什么Autofac不支持
wait/async
,但这似乎是一个简单的解决方案。问题是您希望拦截处理如何等待
任务
s,还是处理实际调用发生的代码。我想这是在截取异步代码时必须记住的事情之一。@Callumlington:要清楚,被截取的代码仍然应该使用
await
。截取代码只是截取返回的
任务
,并将其替换为自己的任务(这恰好是通过
异步
/
等待
实现的)。请注意,截取是由Castle.DynamicProxy而不是Autofac完成的。Autofac只是让连接更容易。正如FYI@StephenCleary一样,调用
WatchAsync
方法时使用的参数数量不正确Sam I correct如果调用返回的任务有参数,此方法将失败?如果是这样,如果我们不想为每个可能被调用的方法编写代码,我们该怎么办?