【问题标题】:How can I make VS break on exceptions in an async Task, without breaking on all exceptions?如何使 VS 中断异步任务中的异常,而不中断所有异常?
【发布时间】:2013-09-28 07:57:33
【问题描述】:

herehere 所示,异步任务中发生的异常在技术上并未得到处理。

在使用 MVC 时,这尤其令人讨厌。实际上,我们花了一段时间才弄明白为什么没有捕获异常的情况越来越多,过去几周我们一直在逐渐将 Web API 调用引入我们的应用程序。

public async Task<ActionResult> Foo()
{
    // ...
}

建议的解决方法是让 VS 在所有异常上中断,而不仅仅是未处理的异常。它的工作原理是令人讨厌的“副作用”,它确实在所有异常情况下都会中断:)

是否有另一种不涉及中断所有异常的解决方法?它可以特定于 MVC,但不一定是(意味着它是否是适用于 MVC 的通用解决方案)。

【问题讨论】:

标签: c# asp.net-mvc visual-studio-2012


【解决方案1】:

按照here 的建议,启用“仅我的代码”是一种方法。诚然,这些异常在技术上并不是未处理的,但它们是未处理的用户代码,这让 VS 做有用的事情并向您显示异常发生的位置。

请参阅this answer 获取一些屏幕截图。

显然,此设置有其他含义(例如,您不能再单步执行框架代码),因此这可能合适,也可能不合适。

【讨论】:

  • 这似乎不会让 VS 中断异步 MVC 操作中发生的未处理异常。
【解决方案2】:

您可以为TaskScheduler.UnobservedTaskException 添加一个处理程序。

但是,也许您已经尝试过,并且想要一种方法使调试器在原始异常处中断,而不是在未观察到的任务异常处理程序中中断。

【讨论】:

    【解决方案3】:

    try-catch reference in MSDN 有一些关于异步方法中的异常的指导和示例,并指出:“由于返回任务的方法中存在未处理的异常,应用等待的已完成任务可能处于错误状态。正在等待任务抛出异常。”

    对于该页面上给出的示例,它指出:“以下示例说明了异步方法的异常处理。要捕获异步任务引发的异常,请将 await 表达式放在 try 块,并在 catch 块中捕获异常。取消注释示例中的 throw new Exception 行以演示异常处理。任务的 IsFaulted 属性为设置为True,任务的Exception.InnerException属性设置为异常,异常被catch块捕获。” p>

    这是那里给出的示例的副本:

    public async Task DoSomethingAsync()
    {
        Task<string> theTask = DelayAsync();
    
        try
        {
            string result = await theTask;
            Debug.WriteLine("Result: " + result);
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Exception Message: " + ex.Message);
        }
        Debug.WriteLine("Task IsCanceled: " + theTask.IsCanceled);
        Debug.WriteLine("Task IsFaulted:  " + theTask.IsFaulted);
        if (theTask.Exception != null)
        {
            Debug.WriteLine("Task Exception Message: "
                + theTask.Exception.Message);
            Debug.WriteLine("Task Inner Exception Message: "
                + theTask.Exception.InnerException.Message);
        }
    }
    
    private async Task<string> DelayAsync()
    {
        await Task.Delay(100);
    
        // Uncomment each of the following lines to 
        // demonstrate exception handling. 
    
        //throw new OperationCanceledException("canceled");
        //throw new Exception("Something happened.");
        return "Done";
    }
    
    // Output when no exception is thrown in the awaited method: 
    //   Result: Done 
    //   Task IsCanceled: False 
    //   Task IsFaulted:  False 
    
    // Output when an Exception is thrown in the awaited method: 
    //   Exception Message: Something happened. 
    //   Task IsCanceled: False 
    //   Task IsFaulted:  True 
    //   Task Exception Message: One or more errors occurred. 
    //   Task Inner Exception Message: Something happened. 
    
    // Output when a OperationCanceledException or TaskCanceledException 
    // is thrown in the awaited method: 
    //   Exception Message: canceled 
    //   Task IsCanceled: True 
    //   Task IsFaulted:  False
    

    【讨论】:

    • 像 OP 所问的那样,以编程方式捕获异常与 VS 打破异常有什么关系?
    【解决方案4】:

    如果这里没有其他方法,您可以尝试收听此事件

    AppDomain.CurrentDomain.UnhandledException
    

    AppDomain.CurrentDomain.FirstChanceException
    

    然后你需要放置一些 if 结构(例如检查什么发件人),只有在有意义的时候才能命中你的断点。

    【讨论】:

      【解决方案5】:

      A) 包装您的调用并在您的任务代码中抛出一个自定义异常。中断只抛出您的自定义异常。您可以选择第一次抛出的异常。

      B)。 Debug.Assert() 你的任务结果,如果你有任何等待代码。即,不仅仅是射击和遗忘。如果您在某处等待任务或继续坚持错误处理,任务会在属性中返回异常。

      伪代码 即任务。 continuewith(r => if(!r.Exception is null) Debug.Break())) 等等

      希望能帮助你走上正确的道路。

      【讨论】:

      • 我喜欢 Debug.Assert 的想法,但我没有看到在 ASP.NET MVC 的上下文中使用这些想法的方法,你有 public async Task&lt;ActionResult&gt; Foo()
      • 简单的方法就是这样。 public async Task Foo(){try{ your code}catch{if(Debugger.IsAttached)Debug.Break();}}
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-03
      • 2012-09-27
      • 2013-05-31
      • 2011-03-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多