2

I've seen similar questions (here and here for instance), but I'm still not sure why my code is behaving the way it is. I'm writing some unit tests that do some thread specific work with async functions, but the problem is that the thrown exception isn't caught. Here's a simple example of what I mean:

    static void Main(string[] args)
    {
        ExecuteWillCatch(async () =>
        {
            await MyTaskFunction();
            throw new Exception("I throw an exception");
        });
    }

    static void MyAction()
    {
        MyTaskFunction();
        throw new Exception("I throw an exception!");
    }

    static async Task MyTaskFunction()
    {
        
    } 
    static void ExecuteWillCatch(Action action)
    {
        var op = new ThreadStart(() =>
        {
            try
            {
                action.Invoke();
            }
            catch (Exception e)
            {
                Console.WriteLine("I caught the exception");
            }

        });
        var thread = new Thread(op);
        thread.Start();
        thread.Join();
    }

If I use an async lambda in my Test, then what happens is the Exception is thrown at the expected target, and then rethrown in mscorlib, and subsequently not caught in the try-catch block in ExecuteWillCatch. If I replace the async/await with just waiting for a result, everything will pass. That's a workaround that I can use, but I'd like to ideally test the code as it will be used (with the async/await). I've also tried putting try-catch blocks in the Main function, and around the thread calls, thinking that maybe the exception is thrown back to that thread, but that isn't the case either.

Can anyone suggest a way to do this, or explain why it doesn't work?

Community
  • 1
  • 1
Kolichikov
  • 2,944
  • 31
  • 46
  • I know the theory, not sure what is happening in your case.To prevent Blue screen Microsoft has put a default exception handler before calling main to handle any unhandled exception as part of the Managed Code. Then at each return from a method has an exception handler which is either 1) The exception handler for the method 2) any exception handler inside the method 3) A exception handler in the parent. So when an exception occurs then exception works it way up the execution stack until an exception handler is found. Often I seen an exception occur in the an exception handler in wrong place. – jdweng Jun 20 '17 at 22:52
  • 1
    See the many existing duplicates. The basic issue here is that, by design, the semantics of async methods is that exceptions thrown in such methods can only be observed via the `Task` representing the method's execution. An `async void` method has no such `Task`, but the same basic rules apply, rendering the exception completely unobservable. Don't use `async void`. Make it `async Task` (i.e. change the parameter from `Action action` to `Func action`), and then `await` the call. – Peter Duniho Jun 21 '17 at 03:13
  • It may help to consider the non-synchronous scenario, i.e. what happens if `MyTaskFunction()` didn't execute synchronously. Then an exception thrown in the continuation that happens after awaiting `MyTaskFunction()` likely would not happen in the same thread where your try/catch is. It would be impossible for that handler to catch the exception, without observing it via `await`. So the rules are, the exception is _always_ unobservable without the `await` (well, you can call `Wait()` on the returned task, but that would be silly, blocking on an asynchronous method like that). – Peter Duniho Jun 21 '17 at 03:15
  • See also https://stackoverflow.com/questions/13696791/task-cancellation-exception-not-bubbling-up-when-using-async-in-method-signature (there can only be five duplicates listed in the actual question) – Peter Duniho Jun 21 '17 at 03:16

0 Answers0