【问题标题】:Exception is not bubbling up异常没有冒泡
【发布时间】:2015-07-03 18:14:21
【问题描述】:

我试图捕捉一个抛出的异常,但它不会冒泡到它被调用的地方。它打破了InsertNewUser 的catch 块,说

“PeakPOS.exe 中出现“System.Exception”类型的异常,但未在用户代码中处理”

如果我单击调试器继续,它会转到某个名为App.g.i.cs 的文件并在我不理解的行上中断,但与中断时的调试有关。之后应用程序终止。

为什么在重新抛出异常然后重新捕获并处理(待处理)时说未处理?


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

【问题讨论】:

  • 您是否尝试取消选中 Break when this Exception occurs 复选框并再次运行?我认为在调试模式下它确实会在异常时中断
  • @Saagar:是的。发生的事情是它进入 App.g.i.cs 文件并像以前一样在 if 语句上中断,它只是不再在 catch 中中断。我想知道我是否误解了try/catch。是不是捕获了异常而不处理它?

标签: c# exception-handling try-catch


【解决方案1】:

这是async 操作的预期行为。您的代码处理/捕获从方法的同步部分抛出的异常,但让应用程序范围的句柄来处理异步部分。

如果您在InsertNewUser 方法(同步部分)的第一行显式抛出异常,您可以观察到预期的行为。

修复:正确地 await 你的 async 方法。

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

比await 方法(注意“异步是病毒式的”-Async/Await Best Practices):

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

或者至少 .Wait 如果它是控制台应用程序(WPF/WinForm/Asp.Net 将死锁 - await vs Task.Wait - Deadlock?):

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

如果你不能这样做 - 至少使用正确的 Fire-and-forget with async vs "old async delegate" 来调用 async void 方法。

注意:async void 是不好的做法,只能用于表单事件。

【讨论】:

  • 谢谢,阿列克谢。有效。感谢这些链接,因为我是 C# 新手,并且只简要浏览了 async/await 功能并且不太了解它。
  • @ShrimpCrackers 欢迎您。如果您需要与async/await 合作,我强烈建议您先浏览Stephen Cleary 的热门答案,然后再在该领域进行任何认真的工作。
【解决方案2】:

我遇到了异常会挂起的问题,但这是因为我正在使用 await 从 Web 服务调用 Web 服务。我的解决办法是申请...

.ConfigureAwait(continueOnCapturedContext: false)

... 在我的内部网络服务调用中。现在,当内部 Web 服务生成异常时,我会按预期收到异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 2011-05-13
    • 2017-07-04
    • 1970-01-01
    • 1970-01-01
    • 2017-08-14
    相关资源
    最近更新 更多