Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception is not bubbling up

I'm trying to catch a thrown Exception, but it doesn't bubble up to where it was called. It breaks in InsertNewUser's catch block, saying

"An exception of type 'System.Exception' occurred in PeakPOS.exe but was not handled in user code"

If I click on debugger Continue, it goes to some file called App.g.i.cs and breaks on a line I don't understand but has something to do with debugging on break. The application terminates after that.

Why is it saying the exception is unhandled when it is being rethrown and then re-caught and handled (to-be handled)?


AccessViewModel.cs

public void SaveNewUser(Popup popup)
{
    UserAccounts.Add(TempUser);

    string salt = PeakCrypto.GenerateSalt();
    string hash = PeakCrypto.GenerateHashedPassword(Password + salt);
    try
    {
        PeakDB.InsertNewUser(TempUser, salt, hash);
    }
    catch (Exception e)
    {
        //TODO notify user that new account could not be saved
    }

    CreateNewAccount();

    if (popup != null)
        popup.IsOpen = false;
}

PeakDB.cs

public static async void InsertNewUser(UserAccount user, String salt, String hash)
{
    var db = await DatabaseHelper.GetDatabaseAsync();

    try
    {
        using (var userStatement = await db.PrepareStatementAsync(
            "INSERT INTO AccessAccounts (FirstName, LastName, Salt, Hash) VALUES(@first, @last, @salt, @hash)"))
        {
            userStatement.BindTextParameterWithName("@first", user.FirstName);
            userStatement.BindTextParameterWithName("@last", user.LastName);
            userStatement.BindTextParameterWithName("@salt", salt);
            userStatement.BindTextParameterWithName("@hash", hash);
            await userStatement.StepAsync();
        }
    }
    catch(Exception e)
    {
        // TODO: log the exception error
        throw;
    }
}

App.g.i.cs

#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
    UnhandledException += (sender, e) =>
    {
        if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
    };
#endif
like image 927
ShrimpCrackers Avatar asked Apr 24 '15 23:04

ShrimpCrackers


2 Answers

This is expected behavior for async operation. Your code handles/catches exceptions thrown from synchronous part of the method, but lets application wide handle to deal with async part.

You can observe behavior you expect if you explicitly throw exception on first line of InsertNewUser method (synchronous part).

Fix: properly await your async method.

// must return at least `Task` to be awaitable
public static async Task InsertNewUser(...

And than await the method (note that "async is viral" - Async/Await Best Practices):

   try
   {
        await PeakDB.InsertNewUser(TempUser, salt, hash);
    }
    catch (Exception e) ...

Or at least .Wait if it console app (WPF/WinForm/Asp.Net will deadlock - await vs Task.Wait - Deadlock?):

   try
   {
        PeakDB.InsertNewUser(TempUser, salt, hash).Wait();
    }
    catch (Exception e) ...

If you can't do either - at least use proper Fire-and-forget with async vs "old async delegate" to call async void methods.

Note: async void is bad practice and should only be used for form events.

like image 58
Alexei Levenkov Avatar answered Sep 16 '22 13:09

Alexei Levenkov


I was having a problem where my exceptions would hang, but it was because I was calling a web service from a web service using await. My fix was to apply ...

.ConfigureAwait(continueOnCapturedContext: false)

... on my inner web service call. Now when then inner web service generates an exception I receive the exception as expected.

like image 20
barrypicker Avatar answered Sep 20 '22 13:09

barrypicker