Catch exception from `await` while maintaining the await returns to the outer scope

async/await
async/await without try-catch
async/await try/catch not working
async/await error handling
async/await catch reject
vue async/await error handling
async/await error handling best practices
better error handling async/await

I have a nice linear code enabled by async await, which returns a value. Most of my code is along this pattern:

var a = await Foo1();
Bar1(a);
Bar2(a);
Bar3(a);

var b = await Foo2(a);
Bar4(a,b);

But then I need to catch the exception from the async function.

try
{
    var a = await Foo1();
}
catch(MyException me)
{
    throw me;
}

Bar1(a);
Bar2(a);
Bar3(a);
try
{
    var b = await Foo2(a);
}
catch(MyException2 me2)
{
    throw me2;
}
Bar4(a,b);

This scopes the variable inside try and it is now a compile error. If I want to maintain linear code, then the try has to cover too many lines which I think it is not a good practice? Now it creates an indented pyramid:

try
{
    var a = await Foo1();
    Bar1(a);
    Bar2(a);
    Bar3(a);
    try
    {
        var b = await Foo2(a);
        Bar4(a, b);
    }
    catch (MyException2 me2)
    {
        throw me2;
    }
}
catch (MyException me)
{
    throw me;
}

So to try only that line and maintain linear code, I need to move the declaration to be nothing at first then assign in the try, to maintain the variable on the outer scope.

A a;
try
{
    a = await Foo1();
}
catch (MyException me)
{
    throw me;
}

Bar1(a);
Bar2(a);
Bar3(a);
B b;
try
{
    b = await Foo2(a);
}
catch (MyException2 me2)
{
    throw me2;
}
Bar4(a, b);

Now it is kinda linear. I have to stop using var too because I can no longer infer from the async method. I feel like C# would have provided a more elegant solution that I am missing?

Common Mistakes in JavaScript Async Function Error Handling, Learn JavaScript Async Function Error Handling, and don't throw an error If an exception is thrown, the trycatch statement catches it. can be manually returned using return to outer scope, but anyway a rejected Apply the DRY principle to make Angular code less error-prone and easier to maintain. Of course, depending on the stuff foo has to execute, it may take some time before the function returns, but this is the beauty of await! Execution of the outer async function will be paused until

I think you can do something like

public struct Result<TResult>
{
    public static Result<TResult> Ok(TResult data) => new Result<TResult>(data, true);
    public static Result<TResult> Error() => new Result<TResult>(default(TResult), false);

    private Result(TResult data, bool success)
    {
        Data = data;
        Success = success;
    }

    public bool Success { get; }
    public TResult Data { get; }
}

public static class TaskExt
{
    public static async Task<Result<T>> AwaitSafe<T, TException>(this Task<T> task, Action<TException> handle)
        where TException : Exception
    {
        var result = Result<T>.Error();
        try
        {
            result = Result<T>.Ok(await task);
        }
        catch (TException ex)
        {
            handle.Invoke(ex);
        }

        return result;
    }
}

Usage:

 public async Task Exec()
    {
        var cli = new HttpClient();
        var result = await cli.GetStringAsync("https://google.com")
           .AwaitSafe((Exception ex) => throw ex);
        if (result.Success)
        {
            //good
        }
        else
        {
            //bad
        }
    }

Asyncio Coroutine Patterns: Errors and cancellation, But sometimes the outside world is not as awesome and we have to deal with it… when using await handle exceptions with try..except as usual. when using We can do that by defining a list of errors in the enclosing scope and mutating done and pending, while gather returns the results of those tasks. In async/await functions it is common to use try/catch blocks to catch such errors. I'm not coming from a typed language background, so the try/catch adds for me additional code that in my opinion doesnt look that clean.

Why not put all code inside the try that needs the variable declared inside the try?

try
{
    var a = await Foo1();
    Bar1(a);
    Bar2(a);
    Bar3(a);
}
catch(MyException me)
{
    // Use `me` or log the event
    throw me;
}

try
{
    var b = await Foo2(a);
    Bar4(a,b);
}
catch(MyException2 me2)
{
    // Use `me2` or log the event
    throw me2;
}

Understanding Control Flow with Async and Await in C#, Once you get the hang of their syntax and usage, it can actually be quite a joy to write asynchronous code. The await keyword does not block the current thread. during a non-blocking wait, it might be helpful to take a step back and The details of the generated code are outside the scope of this guide  Design the ER diagram using what you have learned in the video lecture series we watched. Do not create the database or write SQL. This is a schema design exercise.

This answer is inspired by mtkachenko's answer. The try-catch blocks can be avoided by using the Task.WhenAny method to await safely the Task, and then querying its property IsFaulted to determine if it's safe to access the task's Result.

//var a = await Foo1();
var task1 = await Task.WhenAny(Foo1());
if (task1.IsFaulted) return; // Or do something else
var a = task1.Result;

Bar1(a);
Bar2(a);
Bar3(a);

//var b = await Foo2(a);
var task2 = await Task.WhenAny(Foo2(a));
if (task2.IsFaulted) return; // Or do something else
var b = task2.Result;

Bar4(a, b);

If you think that using the Task.WhenAny for safe awaiting is against the purpose of this method, you could use instead the extension method below:

public static async Task<Task<T>> AwaitSafe<T>(this Task<T> source)
{
    try
    {
        await source.ConfigureAwait(false);
    }
    catch { }
    return source;
}

Usage example:

var task1 = await Foo1().AwaitSafe();

Process-Aware Information Systems: Bridging People and Software , It must also trigger compensation on successfully completed nested scopes in If a handler was found to catch the fault, the activity in the exception handler will run. deal with errors, all the while maintaining familiar graph-based approaches. sure activities with more than one incoming link do not have to wait forever if it  Async/Await. There’s a ton of information about async await support in .NET 4.5. I don’t want to go over all the best practices and gotchas in this post, but I did want to point out one common trend I’ve seen lately, which is handling async await exceptions.

App exits after catching exception thrown by coroutine · Issue #753 , Do exceptions propagated by await() always get rethrown? So you can use an isolated scope, but you apply its rule for all childs in the An async to do something and return a result (or exception or have the whole thing cancel). like sequential code while keeping the benefits of future and callbacks. With async/await we rarely need to write promise.then/catch, but we still shouldn’t forget that they are based on promises, because sometimes (e.g. in the outermost scope) we have to use these methods.

Deeply Understanding JavaScript Async and Await with Examples, Instead of using a normal try/catch , we have to use .catch for error handling. Looping They allow asynchronous execution while maintaining a regular, In this, we are manually returning a promise instead of using async . Because we await the result of waitAndMaybeReject(), its rejection will be turned into a throw, and our catch block will execute. If waitAndMaybeReject() fulfills, we return its result. If the above seems confusing, it might be easier to think of it as two separate steps:

Get in Touch Communicate and Connect, If you dictate on to tape, you can play it back and amend it, but listening to it is not the same technology has been to increase the scope for manuscript communications. When it comes to awaiting for easy reading', the principles have much in in bush a way as to gain the reader's interest' (while retaining credibility and  When an async method is cancelled in debug mode with the option 'Just My Code' enabled, Visual Studio will break and throw an exception. Try running in release mode and see if that resolves the problem.

Comments
  • You obviously need to do something else than throw me(2), because you could just as well leave that out and the same will happen (with a better stack trace). Please edit your question to show what you actually want to do there.
  • If your entire catch block is only going to rethrow it, then the catch has no purpose - just don't catch it at all. A pedantic argument would be the ability to put a breakpoint (this is similar to the difference between var result = Foo(); return result; and return Foo();, it's a matter of easy breaking) But I do agree for non-debug situations.
  • Well then the catch has a purpose :) But still, I just set the Visual Studio debug options to break on all exceptions (not just unhandled ones). That also helps find exceptions that might have been mistakenly swallowed that you would otherwise never see.
  • Using the AwaitSafe how do you know if an exception occurred or not, to continue conditionally in different directions? The only way I see is to update a local variable inside the handle, which is awkward.
  • If you want to stop further execution - just throw. If you don't want to throw - you should use default(T) as a marker that something was wrong. If it's still not obvious you can use MayBe or Result monads mikhail.io/2016/01/monads-explained-in-csharp
  • So if default(T) happens to be a valid return value, the alternative is to delve into the theory of monads?
  • @TheodorZoulias What do you think about my updated answer?
  • Now it's better. This approach is maybe usable. :-)