Luis Ferrao
Luis Ferrao

Reputation: 1503

Async exception not being caught or being swallowed

Update from the future: TL;DR to catch expressions in async methods you have to await, Task.WaitAll, or .Result.

I created a somewhat convoluted async method that just runs other async methods. You can disregard most of it as only the line var mSpekTask... is of interest, also, I don't care about the logic, I only want to know where my exception went. My main problem is that ex.ToString() is never hit even though inside mSpecTask an exception definitly happens.

public async Task LoadAsync(IEnumerable<ProductRequest> feed, int? customerId,
    IProgress<int> mSpecProgress, Action<Task> mSpecCompletionHandler)
{
    var ids = feed.Select(x => x.ProductId.ToString()).Distinct().ToList();

    try
    {
        var mSpecTask = this.LoadMSpecAsync(mSpecProgress, ids);
    }
    catch (Exception ex)
    {
        ex.ToString();
    }
}

Here is the code for LoadMSpecAsync

public Task<ResultSet> LoadMSpecAsync(IProgress<int> prg, IEnumerable<string> ids)
{
    return this.LoadAsync(prg, ids, Selector.M, SPMS, x => x.Order);
}

Here is the code for LoadAsync, await db.ExecuteTVP(progress, spName, ids, parameters) generates an exception.

private async Task<Dictionary<Pair, dynamic>> LoadAsync(IProgress<int> progress,
    IEnumerable<string> ids, Selector s, string spName, Func<dynamic, int> k,
    Func<dynamic, dynamic> f = null, object parameters = null)
{
    parameters = new ExpandoObject().CopyFromSafe(parameters);
    if (spName != SPMAP) ((dynamic)parameters).lang = this.languageCode;

    using (var db = new SqlConnection(this.connectionString))
    {
    await db.OpenAsync();

    var results = await db.ExecuteTVP(progress, spName, ids, parameters);

    db.Close();
    }

    return this.data[s];
}

Upvotes: 0

Views: 2749

Answers (4)

Cryptc
Cryptc

Reputation: 3595

I had an Exception being swallowed by myTask.Wait() (or WaitAsync), but it was a task-nesting issue. That is, when I did the myTask.Wait(), myTask had a passed-in parameter Task that ALSO called myParameterTask.Wait(). The parameter task had its own Exception-catch and no throw, so the originally thrown Exception wasn't propagating back to the calling thread.

I thought there was an issue with myTask.Wait() throwing Exceptions, but it wasn't.

Upvotes: -2

Luis Ferrao
Luis Ferrao

Reputation: 1503

I'm going to add an answer to my own question because there's a useful piece of information that I found out. The intermediary method LoadMSpecAsync is swalloing the exception. For this not to happen it needs a little teak. You need to add the async keyword before the return type and the "await" keyword after "return".

Upvotes: 0

Stephen Cleary
Stephen Cleary

Reputation: 456332

When an async method throws an exception, that exception is placed on the returned Task. It's not raised directly to the caller. This is by design.

So, you have to either await the Task returned from LoadMSpecAsync or have your mSpecCompletionHandler examine its Task argument for exceptions. It will show up there.

Upvotes: 9

RoelF
RoelF

Reputation: 7573

You can handle unobserved Task exceptions as follows:

TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs eventArgs) =>
{
      eventArgs.SetObserved();
      ((AggregateException)eventArgs.Exception).Handle(ex =>
      {
          //TODO: inspect type and handle exception
          return true;
      });
};

Upvotes: 1

Related Questions