【问题标题】:C# break debugger on exception as "Break When Thrown"C# 将异常上的调试器中断为“抛出时中断”
【发布时间】:2018-11-21 22:51:15
【问题描述】:

在我的 asp.net 应用程序中,如果应用程序抛出异常,它会被捕获并提供 500 页。我想在抛出位置破坏调试器。目前我正在使用以下代码sn-p:

           void ExceptionHandler(Exception ex) {
                if (Debugger.IsAttached)
                {
                    Debugger.Break();
                }}

但是,此代码在ExceptionHandler 处中断,而不是在抛出位置处。如何在投掷地点打破?

我不想更改异常设置,因为我想中断到达 ExceptionHandler 的异常,而不是系统恢复的异常。

为了更好地说明我的问题:

class Server // Server owned by third party
{
    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.FirstChanceException += (source, e) =>
        {
            // This does not help, because there are legit exceptions
            Console.WriteLine("FirstChanceException event raised in {0}: \"{1}\"",
                AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
        };
        AppDomain.CurrentDomain.UnhandledException += (source, e) =>
        {
            // This does not help, because exception should be handled by server, otherwise it would shut down
            Console.WriteLine("UnhandledException event raised in {0}: \"{1}\"",
                AppDomain.CurrentDomain.FriendlyName, e.ExceptionObject);
        };

        var app = new Application();
        while (true)
        {
            try
            {
                app.ProcessRequest();
            }
            catch (Exception e)
            {
                // If we get here this mean that something is wrong with application
                // Let's break on line marked as #1
                Console.WriteLine("Server swallowed an exception \"{0}\"", e.Message);
                Debugger.Break(); // Debugger breaks, but no exception dialog, and stack trace in method main
            }
        }
    }
}

class Application
{
    public void ProcessRequest()
    {
        try
        {
            Console.WriteLine("Doing stuff");
            throw new InvalidOperationException("Legit exception handled by application");
        }
        catch (InvalidOperationException ex)
        {
            Console.WriteLine("Application handled exception \"{0}\"", ex.Message);
        }

        throw new InvalidOperationException("Unhandled exception"); // #1. Something is wrong here
    }
}

程序的输出:

Doing stuff
FirstChanceException event raised in ExceptionTest: "Legit exception handled by application"
Application handled exception "Legit exception handled by application"
FirstChanceException event raised in ExceptionTest: "Unhandled exception"
Server swallowed an exception "Unhandled exception"

【问题讨论】:

  • 调试器总是会在Debugger.Break(); 或者在抛出异常而没有人捕捉到它的地方中断。如果您有类似 try { ... } catch { /* dang! */ ExceptionHandler(); } 的内容,您应该仍然可以看到堆栈跟踪,这应该会引导您找到原始异常。我也会将异常传递给ExceptionHandler,以确保它可以随时用于分析。最后一点:这可能不是实现您想要的最佳方式,最终目标到底是什么?
  • 我想用效果更好的东西替换Debugger.Break();。我的目标是打破由全局异常处理程序处理的异常。但不仅仅是中断,而是与异常上下文中断。
  • Debugger.Break(); 不与上下文中断吗?我相当肯定它会在您使用的任何调试程序中为您提供堆栈跟踪?
  • 某事引发了该异常,因此throw 语句的行有问题,包含Debugger.Break() 的行没有问题。我不会调试异常处理程序,而是会调试生成这些异常的类。
  • @user2029276,实际上我们经常启用异常设置,因为你不想使用这种方式,你可以在这里查看所有异常处理最佳实践:stackify.com/csharp-exception-handling-best-practices,也许你可以得到方法你想在那里使用。

标签: c# exception-handling visual-studio-debugging


【解决方案1】:

您可以附加 Visual Studio 调试器(或远程调试器,如果它在单独的机器上运行)。

第 1 步:在 Visual Studio IDE 中配置设置。

从菜单栏中,选择“调试”>“Windows”>“异常设置”。

如果您选择所有异常,这将导致调试器在您附加到正在运行的进程时每个异常(已处理和未处理)之前中断。

第 2 步:附加到您的进程以在 Visual Studio(本地或远程)中对其进行调试。

从菜单栏中,选择“调试”>“附加到进程...”,然后通过进程 ID 找到您的应用程序或 Web 应用程序池。

(注意:如果您是远程调试,则将远程调试器从 Visual Studio 的安装目录复制到远程计算机并以管理员身份运行,以便 Visual Studio 可以连接。通常它默认为端口 4020。)

【讨论】:

  • 我只是指出我不想改变Exception Settings
【解决方案2】:

这称为第一次机会异常处理程序。这是一个例子:

static void Main(string[] args)
    {
        AppDomain.CurrentDomain.FirstChanceException +=
        (object source, FirstChanceExceptionEventArgs e) =>
        {
            Console.WriteLine("FirstChanceException event raised in {0}: {1}",
                AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
        };

        try
        {
            Console.WriteLine("Doing stuff");
            throw new ArgumentNullException("Super awesome exception");
        }
        catch (Exception e)
        {
            Console.WriteLine("Caught an exception {0}", e.Message);
        }
    }

或在 msdn 文档中查看: https://docs.microsoft.com/en-us/dotnet/framework/app-domains/how-to-receive-first-chance-exception-notifications

第一次遇到异常时的调用堆栈将显示“throw”作为调用堆栈上的先前位置。

更新:

在“抛出”期间不会处理第二次机会异常。这是根据定义。堆栈跟踪具有抛出位置。

所以你可以 - 打破第一次机会并忽略你不关心的异常(只需重新抛出它们) - 打破第二次机会异常并检查堆栈跟踪以确定它们来自哪里

你不能在第二次机会处理者的“投掷”上打破。他们不是这样工作的。

【讨论】:

  • 感谢您的帮助,但这不是我想要的。我想打破“第二次机会异常”,但从服务器代码的角度来看。换句话说 - 我的应用程序可以从某些异常中恢复,我想忽略这些。这就是为什么FirstChanceException 不适合我。更新了问题代码以更好地说明此问题。
  • @user2029276,我更新了我的答案,你可以检查一下:)
  • Break on first chance and ignore the exceptions you don’t care about - 我不能,因为我只对没有匹配捕获的异常感兴趣,这是在第一次通过后确定的。 Break on second chance exceptions and inspect the stack trace to determine where they came from - 这就是我现在所拥有的,但是在控制台应用程序上工作的体验要好得多,因为第二次机会异常得到了很好的处理。在服务器场景中,您必须与这种行为作斗争。
  • @user2029276,这些是我现在可以提供的解决方案,没有其他好的建议。但如果您有其他建议或反馈,您可以直接向产品团队提交用户声音:visualstudio.uservoice.com/forums/121579-visual-studio
猜你喜欢
  • 2010-11-16
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-17
相关资源
最近更新 更多