7

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
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
ShrimpCrackers
  • 4,388
  • 17
  • 50
  • 76
  • Did you try unchecking the checkbox saying `Break when this Exception occurs` and run again? I think while in debug mode it does break at exception – Saagar Elias Jacky Apr 25 '15 at 00:05
  • @Saagar: Yes. What happens is it goes to the App.g.i.cs file and breaks on the if statement just as before, it just doesn't break in catch anymore. I wonder if I'm misunderstanding try/catch. Is catching an exception not handling it? – ShrimpCrackers Apr 25 '15 at 00:08

2 Answers2

6

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.

Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • Thanks, Alexei. It worked. Appreciate the links since I'm new to C# and have only briefly skimmed async/await feature and do not understand it very well. – ShrimpCrackers Apr 25 '15 at 00:30
  • @ShrimpCrackers welcome. If you need to work with `async`/`await` I strongly suggest to scan through top answers by [Stephen Cleary](http://stackoverflow.com/users/263693/stephen-cleary) before doing any serious work in that area. – Alexei Levenkov Apr 25 '15 at 00:51
1

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.

barrypicker
  • 9,740
  • 11
  • 65
  • 79