【问题标题】:Async exception not caught by debugger调试器未捕获异步异常
【发布时间】:2014-06-03 03:05:56
【问题描述】:

我正在 VS2013 中开发一个 MVC5 项目。我似乎发现调试器忽略了我的大多数(但不是全部)异常,因此我最终将异常和堆栈跟踪简单地写入浏览器,从而排除了对涉及的对象的任何检查例外。

例如 - 我故意编写一个异常来证明这一点:

    <Authorize(Roles:="IdentityAdmin")>
Public Async Function Import(model As RegisterViewModel) As Task(Of ActionResult)
    Dim a As Object = "he"
    Dim b As Integer = a

很明显,最后一行将引发“类型不匹配”异常,我认为这会导致调试器停止执行,并在 VS2013 UI 中突出显示错误,以便我检查各种对象并确定问题。

相反,我只是发现自己使用浏览器详细说明异常并且 VS2013 无响应:

“/”应用程序中的服务器错误。

输入字符串的格式不正确。

描述:执行过程中发生了未处理的异常 当前的网络请求。请查看堆栈跟踪以获取更多信息 有关错误的信息以及它在代码中的来源。

异常详细信息:System.FormatException:输入字符串不在 格式正确。

来源错误:

第 291 行:如果 Db.Users.Find(acct.username) 什么都没有,那么

第 292 行:将对象变暗 = "he"

第 293 行:将 b 调暗为 Integer = a

当我将相同的异常生成代码插入代码的非异步部分时,VS 调试器 确实 会捕获异常 - 所以我猜这是调试异步代码的问题。 VS调试器真的无法捕捉到这些异常吗?

更新

经过进一步搜索,我发现了一个建议,即禁用“仅我的代码”并手动启用各种类型的异常。有预期的第一次机会异常的冰雹,我可以通过禁用某些异常来调整其中的大部分。但这 DID “修复”了上述行为。调试器似乎将我的子异步线程视为“不是我的代码”。有点困惑,但我想这可能是某种答案?

【问题讨论】:

  • 这对我也有用!如果您回答自己的问题,我(和其他人)可以投票。我投票赞成你所有其他的帖子来给你更多的代表,因为当代表低于 50 时会有一些限制。
  • 另外,在问题和标签中添加了“异步”。
  • 是的,这就是答案。 “只是我的代码”应该(IMO)始终被关闭 - 它会产生问题/混乱,并且不会增加太多价值。

标签: exception visual-studio-2013 async-await visual-studio-debugging


【解决方案1】:

根据上面的更新,问题中详述的问题行为似乎可以通过以下组合来解决:

  • 在调试器选项中关闭“仅我的代码”。
  • 在 Debug/Exceptions 中启用某些类别的异常.. - 在我的情况下,Common Language Runtime Exceptions 和 Managed Debugging Assistants 似乎可以确保调试器捕获我的所有异常(异步或其他)。
  • 禁用引发的(但不起眼的)异常,这些异常会导致最严重的问题(错误的全球化等)。

最后两个阶段在某种程度上是通过反复试验而发生的,我怀疑在清理项目时我最终应该追查大多数这些非破坏性异常。

【讨论】:

    【解决方案2】:

    在这种情况下,禁用“仅我的代码”不会有什么不同,启用“抛出异常时中断”是您希望使调试器停止在正确位置的原因。

    问题在于,当您将方法设为异步时,它会在后台任务中运行。任务将捕获它正在执行的代码中发生的任何异常,并将该异常重新抛出到使用任务结果的任何地方。因此,例如,如果您有以下 MVC 代码

    Async Function Index() As Task(Of ActionResult)
        Dim n as Integer = Await Method1()
        Return View()
    End Function
    
    Async Function Method1() As Task(Of Integer)
       Dim a As Integer = 0
       Dim b As Integer = 1 / b
       Return b
    End Function
    

    在 Method1 内部执行代码的 Task 将捕获异常,并将其抛出到 Index 中,因为它正在使用 Method1 的结果,然后执行 Index 的 Task 将捕获该异常并将其重新抛出到 MVC 框架代码中正在使用Index的结果,然后MVC框架处理异常并显示错误页面。

    启用“仅我的代码”并且方法同步执行时,当异常从用户代码传播出去并显示“用户未处理”消息时,调试器将停止。在上述情况下,如果异常从 Index 传播到不是您的代码的 MVC 框架,则启用 JMC 时调试器将停止。由于在异步方法的情况下,异常不是未处理而是由任务捕获,它不会跨越用户代码,因此禁用只是我的代码不会有什么不同。

    与此相反,如果您的同步方法中发生异常并且您禁用了 Just My Code,则调试器无论如何都不会停止,因为当 JMC 和 MVC 框架被禁用时没有“用户未处理”的概念将最终处理该异常。

    【讨论】:

    • 非常有趣,谢谢。我提出的 JMC 解决方案确实在与启用“异常...”结合使用时似乎有效,但刚刚尝试过您的建议(启用 JMC,将 CLR 异常设置为 Thrown=true)似乎也是一个答案 - 如果它在所有情况下都有效并且在禁用第一次机会异常方面感觉不那么“命中注定”,那么它可能是更好的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    • 2020-08-24
    • 1970-01-01
    • 2011-08-12
    • 2013-04-20
    • 1970-01-01
    • 2014-12-01
    相关资源
    最近更新 更多