0

I'm trying to log a response to a database inside of a delegating handler. Since I want to return the response without waiting for the record to be saved to the database, I want to do that part with an async task.

My problem is, if anything goes wrong within that task, the error cannot be caught and the API crashes with the error

System.Exception: 'Exception of type 'System.Exception' was thrown.'

I've recreated a minimal case below:

public class LogDelegatingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        try
        {
            //send request and get response
            var response = await base.SendAsync(request, cancellationToken);

            //return response while this runs
            _ = Task.Run(() => Log());
  //Task.Run(() => Log()); //also crashes
  //await Task.Run(() => Log()); //also crashes
            return response;
        }

        catch (Exception e)
        {
           //this is never reached
        }
    }

    private async void Log()
    {

        try
        {
            //this crashes 
            throw new Exception("test");
        }
        catch (System.AggregateException e)
        {
           //this is never reached
        }
    }
}

After reading SO and finding a thread where the user did care about exceptions thrown, I wanted to ask this where in my case I don't care, but I do want the response to come through first. After reading this How to safely call an async method in C# without await

I added the _ to dispose of the task and not await it.

NetHawk
  • 1,392
  • 1
  • 15
  • 33
  • 3
    you should never have an `async void` method, the best practice is `async Task` – Tal Feb 14 '20 at 19:39

2 Answers2

2

That's because you are throwing an Exception but attempt to catch AggregateException. Try this:

        try
        {
            //this crashes 
            throw new Exception("test");
        }
        catch (System.AggregateException e)
        {
           // handle in case of aggregate exception
        }
        catch (Exception ex)
        {
           // in case of other exceptions
        }
Tal
  • 548
  • 3
  • 8
0

The catch in SendAsync() is never reached because Log() is async void instead async Task.

You should only ever use async void for fire-and-forget stuff like event. If you want anything back from it, even exceptions, you need to use a Task

Tudor Carean
  • 972
  • 2
  • 12
  • 22