0

Per the answer to this question, the form for capturing an exception thrown by an asynchronous method looks like this:

public async void DoFoo()
{
    try
    {
        await Foo();
    }
    catch (ProtocolException ex)
    {
          /* The exception will be caught because you've awaited the call. */
    }
}

Great. This seems to disintegrate if I want to bubble up several levels of asynchrony though. Here's where the exception originates:

internal static async Task MakePdfPagesFromPdf(Pdf pdf, byte[] pdfBytes, int jobId)
{
    IEnumerable<Image> pdfAsImages = PdfOperations.PdfToImagesPdfium(pdfBytes, dpi);

    if(pdfAsImages.Count() < 1)
    {
        throw new ArgumentException("PDF has no pages.");
    }

    // ... more code ...
}

Here's the method that calls MakePdfPagesFromPdf:

internal static async Task ProcessBase64Pdf(Pdf pdf, int jobId, string componentDesignName)
{
    byte[] pdfBytes = ConvertBase64ToPdfByteArray(pdf.Url); // Base64 data is in pdf.Url
    await UploadPdfToAwsS3(pdf, pdfBytes, jobId, componentDesignName);
    try
    {
        await MakePdfPagesFromPdf(pdf, pdfBytes, jobId);
    }
    catch(ArgumentException argumentException)
    {
        throw argumentException;
    }
}

I catch the exception like in the example cited at the beginning of this question. Debugging asserts that this catch block is hit. However, I need to bubble the exception up one more level, to inside a controller route:

try
{
    await PdfsController.ProcessBase64Pdf(pdf, componentDesign.JobId, componentDesign.Name);
}
catch (ArgumentException argumentException)
{
    // Now do stuff with the exception                  
}

It doesn't hit this highest level catch at a breakpoint. Removing the intermediate catch has no effect. The route continues and returns, but I am not able to hit breakpoints after the ArgumentException is thrown from the intermediate catch. What's going on here and how can I hit breakpoints through this whole asynchronous stack?

Community
  • 1
  • 1
Scotty H
  • 6,432
  • 6
  • 41
  • 94
  • 2
    Maybe you can provide minimal complete example? It should bubble up to top level catch. – Evk Apr 19 '16 at 20:44
  • @Evk Thanks, I've determined it does. I edited the question title and content to be about debugging. I thought it wasn't working because I wasn't hitting breakpoints in the highest level inside the catch, but I noticed right after posting that I was actually getting the email it sent. – Scotty H Apr 19 '16 at 20:46
  • 1
    Still minimal complete example won't hurt :) Because it should hit breakpoint in top level catch also. Maybe that's some obvious thing like your source code is not up to date? Is breakpoint red or white? – Evk Apr 19 '16 at 20:57
  • This is really strange. Your example should work. You could try to check what the tasks do and what states they switch to. I do not recommend this in productive code but for debugging it may be useful to wait for the tasks synchronously and check if they properly switch to the faulted state once the exception occurs. – Nitram Apr 19 '16 at 22:37
  • Regarding the `MakePdfPagesFromPdf` method, do you get a compiler warning [CS1998](https://stackoverflow.com/questions/37594737/what-is-the-reason-behind-cs1998-method-lacks-await-operators) *"This async method lacks 'await' operators and will run synchronously"*? – Theodor Zoulias Jul 23 '21 at 14:04

2 Answers2

2

If the method that you want to propogate the exception is async void (such as in your example of DoFoo), then the issue is that there is no Task object to propagate the exception with (since the method is void and does not return a Task)

Another thing I suggest is to not throw argumentException, but rather just throw, as the former loses the call stack of the original exception

Itsik
  • 3,920
  • 1
  • 25
  • 37
  • [Here](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#avoid-async-void) is explained in more details why `async void` should be avoided. – Theodor Zoulias Jul 23 '21 at 14:07
-1

I'm guessing Argument exception is part of an inner exception. And is not the thrown exception. You should change catch (ArgumentException argumentException) to catch (ArgumentException exception) to call "all" exceptions.

Kevin Up
  • 791
  • 1
  • 6
  • 11