Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I need to call an async method in a catch block before throwing again the exception (with its stack trace) like this :

try
{
    // Do something
}
catch
{
    // <- Clean things here with async methods
    throw;
}

But unfortunately you can't use await in a catch or finally block. I learned it's because the compiler doesn't have any way to go back in a catch block to execute what is after your await instruction or something like that...

I tried to use Task.Wait() to replace await and I got a deadlock. I searched on the Web how I could avoid this and found this site.

Since I can't change the async methods nor do I know if they use ConfigureAwait(false), I created these methods which take a Func<Task> that starts an async method once we are on a different thread (to avoid a deadlock) and waits for its completion:

public static void AwaitTaskSync(Func<Task> action)
{
    Task.Run(async () => await action().ConfigureAwait(false)).Wait();
}

public static TResult AwaitTaskSync<TResult>(Func<Task<TResult>> action)
{
    return Task.Run(async () => await action().ConfigureAwait(false)).Result;
}

public static void AwaitSync(Func<IAsyncAction> action)
{
    AwaitTaskSync(() => action().AsTask());
}

public static TResult AwaitSync<TResult>(Func<IAsyncOperation<TResult>> action)
{
    return AwaitTaskSync(() => action().AsTask());
}

So my questions is: Do you think this code is okay?

Of course, if you have some enhancements or know a better approach, I'm listening! :)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
427 views
Welcome To Ask or Share your Answers For Others

1 Answer

You can move the logic outside of the catch block and rethrow the exception after, if needed, by using ExceptionDispatchInfo.

static async Task f()
{
    ExceptionDispatchInfo capturedException = null;
    try
    {
        await TaskThatFails();
    }
    catch (MyException ex)
    {
        capturedException = ExceptionDispatchInfo.Capture(ex);
    }

    if (capturedException != null)
    {
        await ExceptionHandler();

        capturedException.Throw();
    }
}

This way, when the caller inspects the exception's StackTrace property, it still records where inside TaskThatFails it was thrown.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...