只在异步方法

时间:2018-01-27 05:14:30

标签: c# .net asynchronous exception idisposable

我想更详细地了解.Net异常过滤器的工作原理,特别是async方法和IDisposable块中的using个对象。

async ASP.Net Core请求委托的异常过滤器中有一个GitHub issue关于日志记录范围丢失的问题。范围存储在ConsoleLogScope中,并且在丢弃一次性物品时丢失。

在以下代码中,演示了两种情况:

第一:

  • 同步RequestDelegate引发异常
  • 执行异常过滤器并返回
  • ConsoleLogScope.DisposableScope已被处理

第二

  • 异步RequestDelegate引发异常
  • ConsoleLogScope.DisposableScope已被处理
  • 执行异常过滤器并返回

请注意,仅将lambda标记为async足以引入第二种行为。 GitHub问题表明它归因于await Task.Delay(100),但我和#39;我发现它没有那条线。

这是为什么?它是AsyncTaskMethodBuilder捕获异常,所以过滤器永远不会被执行吗?

public class Program
{
    public static void Main(string[] args)
    {
        new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .ConfigureLogging(logging =>
            {
                logging.AddConsole(options => options.IncludeScopes = true);
                logging.AddFilter("Microsoft", LogLevel.Warning);
            })
            .Configure(app =>
            {
                var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>();

                app.Map("/sync", subApp =>
                {
                    // Exception handler
                    subApp.Use(async (context, next) =>
                    {
                        try
                        {
                            await next();
                        }
                        catch (Exception ex) when (LogError(logger, ex))
                        {
                        }
                    });
                    // Logic
                    subApp.Run((context) =>
                    {
                        using (logger.BeginScope("UserId:100"))
                        {
                            throw new InvalidOperationException("Something went wrong");
                        }
                    });
                });

                app.Map("/async", subApp =>
                {
                    // Exception handler
                    subApp.Use(async (context, next) =>
                    {
                        try
                        {
                            await next();
                        }
                        catch (Exception ex) when (LogError(logger, ex))
                        {
                        }
                    });
                    // Logic
                    subApp.Run(async (context) =>
                    {
                        using (logger.BeginScope("UserId:100"))
                        {
                            await Task.Delay(100); // Force TaskAwaiter
                            throw new InvalidOperationException("Something went wrong");
                        }
                    });
                });
            })
            .Build()
            .Run();
    }

    public static bool LogError(ILogger logger, Exception ex)
    {
        logger.LogError(ex, "Unhandled exception");
        return true;
    }
}

0 个答案:

没有答案