title: IDisposable disposed before exception filter only in async methods
body: <p>I would like to understand in more detail how .Net Exception Filters work, specifically with regards to <code>async</code> methods and <code>IDisposable</code> objects in <code>using</code> blocks.</p>
  
  <p>There is a <a href="https://github.com/aspnet/Logging/issues/677" rel="nofollow noreferrer">GitHub issue</a> regarding logging scope being lost in exception filters for <code>async</code> ASP.Net Core request delegates. The scope is stored in <a href="https://github.com/aspnet/Logging/blob/dev/src/Microsoft.Extensions.Logging.Console/ConsoleLogScope.cs#L54" rel="nofollow noreferrer"><code>ConsoleLogScope</code></a> and is lost when the disposable is disposed. </p>
  
  <p>In the following code, there are two scenarios demonstrated:</p>
  
  <p>First: </p>
  
  <ul>
  <li>Synchronous RequestDelegate throws an exception</li>
  <li>Exception filter is executed and returns</li>
  <li><code>ConsoleLogScope.DisposableScope</code> is disposed</li>
  </ul>
  
  <p>Second:</p>
  
  <ul>
  <li>Asynchronous RequestDelegate throws an exception</li>
  <li><code>ConsoleLogScope.DisposableScope</code> is disposed</li>
  <li>Exception filter is executed and returns</li>
  </ul>
  
  <p><strong>Note that merely marking the lambda as <code>async</code> is sufficient to introduce the second behaviour.</strong> The GitHub issue says it's due to the <code>await Task.Delay(100)</code>, but I've found it happens without that line.</p>
  
  <p>Why is this? Is it <code>AsyncTaskMethodBuilder</code> catching exceptions, so the filters never get executed?</p>
  
  <pre><code>public class Program
  {
      public static void Main(string[] args)
      {
          new WebHostBuilder()
              .UseKestrel()
              .UseContentRoot(Directory.GetCurrentDirectory())
              .ConfigureLogging(logging =&gt;
              {
                  logging.AddConsole(options =&gt; options.IncludeScopes = true);
                  logging.AddFilter("Microsoft", LogLevel.Warning);
              })
              .Configure(app =&gt;
              {
                  var logger = app.ApplicationServices.GetRequiredService&lt;ILogger&lt;Program&gt;&gt;();
  
                  app.Map("/sync", subApp =&gt;
                  {
                      // Exception handler
                      subApp.Use(async (context, next) =&gt;
                      {
                          try
                          {
                              await next();
                          }
                          catch (Exception ex) when (LogError(logger, ex))
                          {
                          }
                      });
                      // Logic
                      subApp.Run((context) =&gt;
                      {
                          using (logger.BeginScope("UserId:100"))
                          {
                              throw new InvalidOperationException("Something went wrong");
                          }
                      });
                  });
  
                  app.Map("/async", subApp =&gt;
                  {
                      // Exception handler
                      subApp.Use(async (context, next) =&gt;
                      {
                          try
                          {
                              await next();
                          }
                          catch (Exception ex) when (LogError(logger, ex))
                          {
                          }
                      });
                      // Logic
                      subApp.Run(async (context) =&gt;
                      {
                          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;
      }
  }
  </code></pre>