1

We get the following AggregateException in the following piece of code, and we don't understand how we can catch this exception. The code is in a asp.net core SignalR server application.

Any suggestion?

public async Task MetricsStream(IAsyncEnumerable<ReadPointMetrics> stream)
{
    try
    {
        await foreach (var metrics in stream) // this is line 224
        {
            try
            {
                await readerDeviceHub.StoreMetrics(readerId, metrics);
            } catch (Exception e)
            {
                // we don't end up here
                log?.Error(e, "Error in storing metrics");
            }
        }
    } catch (Exception e)
    {
        // we don't end up here
        log?.Warning(e, "Exception in metrics stream");
    }
}
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. (Stream canceled by client.)
 ---> System.Exception: Stream canceled by client.
   at System.Threading.Channels.AsyncOperation`1.GetResult(Int16 token)
   at System.Threading.Channels.ChannelReader`1.ReadAllAsync(CancellationToken cancellationToken)+MoveNext()
   at System.Threading.Channels.ChannelReader`1.ReadAllAsync(CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource<System.Boolean>.GetResult()
   at HarmonyBackend.Hubs.ReaderDeviceV1Hub.MetricsStream(IAsyncEnumerable`1 stream) in /builds/nedap-harmony/harmony/HarmonyBackend/Hubs/ReaderDeviceV1Hub.cs:line 224
   at HarmonyBackend.Hubs.ReaderDeviceV1Hub.MetricsStream(IAsyncEnumerable`1 stream) in /builds/nedap-harmony/harmony/HarmonyBackend/Hubs/ReaderDeviceV1Hub.cs:line 224
   --- End of inner exception stack trace ---
Danny
  • 411
  • 1
  • 3
  • 8
  • Does this work: public void MetricsStream(IEnumerable streamCollection) { try { foreach (var metrics in streamCollection) // this is line 224 { Task.Run(() => readerDeviceHub.StoreMetrics(readerId, metrics)); } } catch (Exception e) { // we don't end up here log?.Warning(e, "Exception in metrics stream"); } } – The OrangeGoblin Oct 06 '22 at 11:49
  • No - this doesn't work with SignalR - the signature needs to be an async task with IAsyncEnumerable. – Danny Oct 07 '22 at 12:32
  • Is this connected with this problem? https://stackoverflow.com/questions/59020363/try-catch-using-iasyncenumerable-in-signalr-asp-net-core-3-0 – Karel Křesťan Oct 15 '22 at 17:14
  • I don't remember exactly but I had a similar problem in one of my projects and the one thing I remember is I used CancelationToken and a finally block to handle the enumerator disposal manually and It solved the problem. unfortunately, your code is not reproducible, So I'm not sure how can I help you further. – AliReza Sabouri Oct 18 '22 at 18:27

1 Answers1

1

You can capture in the caller to MetricsStream function with a WaitAll. If you have linqpad, this example will simulate what you are getting.

async void Main()
{
    var tasks = new [] {
        Success(),
        Fail(),
    };
    
    try
    {
        //await Task.WhenAll(tasks);    // will get Exception("Kaboom!"
        Task.WaitAll(tasks); // will Get Agggregate Exception
    }
    catch(AggregateException ex)
    {
        Console.WriteLine("Aggregate Exception");
        // can grab the inner exceptions.
        ex.Dump();
    }
    catch(Exception ex)
    {
        ex.Dump();
    }
    
    
}

async Task Success()
{
    await Task.Delay (TimeSpan.FromSeconds(5));
    return;
}

async Task Fail()
{
    await Task.Delay (TimeSpan.FromSeconds (5));
    throw new Exception("Kaboom!");
}
Jim
  • 864
  • 1
  • 8
  • 16
  • Because this function is part of a SignalR Hub, we're actually not calling this function anywhere in our code, so that's why we cannot have exception handlers around the function. – Danny Oct 19 '22 at 22:17
  • you can wrap your try catch in a task and await that wrapped task. the wrapped task should throw the aggregate exception. – Jim Oct 21 '22 at 13:41