BackgroundWorker 中未处理的异常

发布于 2024-07-25 16:06:31 字数 884 浏览 1 评论 0原文

我有一个小型 WinForms 应用程序,它利用 BackgroundWorker 对象来执行长时间运行的操作。

后台操作偶尔会引发异常,通常是当有人打开正在重新创建的文件时。

无论代码是否从 IDE 运行,.NET 都会弹出一个错误对话框,通知用户发生了未处理的异常。 使用发布配置编译代码也不会改变这一点。

根据 MSDN

如果操作引发代码无法处理的异常,BackgroundWorker 会捕获该异常并将其传递到 RunWorkerCompleted 事件处理程序,在该处理程序中该异常将作为 System.ComponentModel..::.RunWorkerCompletedEventArgs 的 Error 属性公开。 如果您在 Visual Studio 调试器下运行,则调试器将在 DoWork 事件处理程序中引发未处理异常的位置处中断。

我希望偶尔会抛出这些异常,并希望在 RunWorkerCompleted 事件中而不是在 DoWork 中处理它们。 我的代码工作正常,错误在 RunWorkerCompleted 事件中得到正确处理,但我一生都无法弄清楚如何阻止 .NET 错误对话框抱怨“未处理的异常”发生。

BackgroundWorker 不是应该自动捕获该错误吗? MSDN文档不是这么说的吗? 我需要做什么才能通知 .NET 该错误正在处理,同时仍允许异常传播到 RunWorkerCompletedEventArgs 的 Error 属性中?

I have a small WinForms app that utilizes a BackgroundWorker object to perform a long-running operation.

The background operation throws occasional exceptions, typically when somebody has a file open that is being recreated.

Regardless of whether the code is run from the IDE or not .NET pops up an error dialog informing the user that an Unhandled exception has occurred. Compiling the code using the Release configuration doesn't change this either.

According to MSDN:

If the operation raises an exception that your code does not handle, the BackgroundWorker catches the exception and passes it into the RunWorkerCompleted event handler, where it is exposed as the Error property of System.ComponentModel..::.RunWorkerCompletedEventArgs. If you are running under the Visual Studio debugger, the debugger will break at the point in the DoWork event handler where the unhandled exception was raised.

I expect these exceptions to be thrown on occasion and would like to handle them in the RunWorkerCompleted event rather than in DoWork. My code works properly and the error is handled correctly within the RunWorkerCompleted event but I can't for the life of me figure out how to stop the .NET error dialog complaining about the "Unhandled exception" from occurring.

Isn't the BackgroundWorker supposed to catch that error automagically? Isn't that what the MSDN documentation states? What do I need to do to inform .NET that this error is being handled while still allowing the exception to propage into the Error property of RunWorkerCompletedEventArgs?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

烈酒灼喉 2024-08-01 16:06:31

您所描述的不是BackgroundWorker 的定义行为。 我怀疑你做错了什么。

这里有一个小示例,证明BackgroundWorker在DoWork中处理异常,并在RunWorkerCompleted中为您提供它们:

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        if(e.Error != null)
        {
            MessageBox.Show("There was an error! " + e.Error.ToString());
        }
    };
worker.RunWorkerAsync();

我的通灵调试技巧向我揭示了您的问题:您正在访问e RunWorkerCompleted 处理程序中的 .Result - 如果存在 e.Error,则必须在不访问 e.Result 的情况下处理它。 例如,以下代码很糟糕,很糟糕,很糟糕,并且会在运行时引发异常:

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        // OH NOOOOOOOES! Runtime exception, you can't access e.Result if there's an
        // error. You can check for errors using e.Error.
        var result = e.Result; 
    };
worker.RunWorkerAsync();

这是 RunWorkerCompleted 事件处理程序的正确实现:

private void RunWorkerCompletedHandler(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error == null)
    {
       DoSomethingWith(e.Result); // Access e.Result only if no error occurred.
    }
}

瞧,您不会收到运行时异常。

What you're describing is not the defined behavior of BackgroundWorker. You're doing something wrong, I suspect.

Here's a little sample that proves BackgroundWorker eats exceptions in DoWork, and makes them available to you in RunWorkerCompleted:

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        if(e.Error != null)
        {
            MessageBox.Show("There was an error! " + e.Error.ToString());
        }
    };
worker.RunWorkerAsync();

My psychic debugging skills are revealing your problem to me: You are accessing e.Result in your RunWorkerCompleted handler -- if there's an e.Error, you must handle it without accessing e.Result. For example, the following code is bad, bad, bad, and will throw an exception at runtime:

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        // OH NOOOOOOOES! Runtime exception, you can't access e.Result if there's an
        // error. You can check for errors using e.Error.
        var result = e.Result; 
    };
worker.RunWorkerAsync();

Here's a proper implementation of the RunWorkerCompleted event handler:

private void RunWorkerCompletedHandler(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error == null)
    {
       DoSomethingWith(e.Result); // Access e.Result only if no error occurred.
    }
}

VOILA, you won't receive runtime exceptions.

゛时过境迁 2024-08-01 16:06:31

我将添加到 MSDN 文本

如果操作引发代码无法处理的异常,BackgroundWorker 会捕获该异常并将其传递到 RunWorkerCompleted 事件处理程序,在该处理程序中该异常将作为 System.ComponentModel..::.RunWorkerCompletedEventArgs 的 Error 属性公开。 如果您在 Visual Studio 调试器下运行,调试器将在 DoWork 事件处理程序中引发未处理异常的位置处中断。

...并且调试器将报告异常为“~Exception was unhandled by user code”

解决方案:不要在调试器下运行,它会按预期工作:异常捕获在 e.Error 中。

I would add to the MSDN text:

If the operation raises an exception that your code does not handle, the BackgroundWorker catches the exception and passes it into the RunWorkerCompleted event handler, where it is exposed as the Error property of System.ComponentModel..::.RunWorkerCompletedEventArgs. If you are running under the Visual Studio debugger, the debugger will break at the point in the DoWork event handler where the unhandled exception was raised.

... AND the debugger will report the exception as "~Exception was unhandled by user code"

Solution: Don't run under the debugger and it works as expected: Exception caught in e.Error.

音盲 2024-08-01 16:06:31

[编辑]

犹大有一个很好的观点。 我的示例指出了处理错误的细节,但如果 DoWork 方法中从未遇到异常,我的代码实际上会导致另一个异常。 这个例子是可以的,因为我们专门展示了BackgroundWorker的错误处理能力。 但是,如果您没有检查错误参数是否为空,那么这可能是您的问题。

[/Edit]

我没有看到相同的结果。 你能发布一些代码吗? 这是我的代码。

private void Form1_Load(object sender, EventArgs e)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.RunWorkerAsync();
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Will cause another exception if an exception didn't occur.
    // We should be checking to see if e.Error is not "null".
    textBox1.Text = "Error? " + e.Error;
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 0; i < 10; i++)
    {
        if (i < 5)
        {
            Thread.Sleep(100);
        }
        else
        {
            throw new Exception("BOOM");
        }   
    }
}

程序输出:

错误? 系统异常:BOOM at
BackgroundException.Form1.worker_DoWork(对象
发送者、DoWorkEventArgs e) 中
D:\Workspaces\Sandbox\BackgroundException\BackgroundException\Form1.cs:line
43 于
System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs

System.ComponentModel.BackgroundWorker.WorkerThreadStart(对象
论证)

一篇有趣的文章,看起来与你的问题相似。 它有一个关于处理异常的部分。

http://www.developerdotstar.com/community/node/671

[Edit]

Judah has a great point. My example pointed out the specifics of handling the error but my code would actually cause another exception if an exception was never hit in the DoWork method. This example is OK due to the fact that we are specifically showing the error handling capabilities of the BackgroundWorker. However if you are not checking the error parameter against null then this could be your issue.

[/Edit]

I don't see the same results. Can you post a little code? Here is my code.

private void Form1_Load(object sender, EventArgs e)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.RunWorkerAsync();
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Will cause another exception if an exception didn't occur.
    // We should be checking to see if e.Error is not "null".
    textBox1.Text = "Error? " + e.Error;
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 0; i < 10; i++)
    {
        if (i < 5)
        {
            Thread.Sleep(100);
        }
        else
        {
            throw new Exception("BOOM");
        }   
    }
}

Program Output:

Error? System.Exception: BOOM at
BackgroundException.Form1.worker_DoWork(Object
sender, DoWorkEventArgs e) in
D:\Workspaces\Sandbox\BackgroundException\BackgroundException\Form1.cs:line
43 at
System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs
e) at
System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object
argument)

An interesting article that looks similar to your question. It has a section on handling exceptions.

http://www.developerdotstar.com/community/node/671

别闹i 2024-08-01 16:06:31

这是一个老问题,但我在谷歌搜索相同的症状时发现了它。 发布此内容以防其他人出于同样的原因发现它。

Judah 的答案是正确的,但这并不是出现“用户代码中未处理的异常”对话框的唯一原因。 如果从后台线程的构造函数内部抛出异常,则该异常将立即引发对话框,并且不会传递给 RunWorkerCompleted 事件。 如果将有问题的代码移到任何构造函数之外(到任何其他方法),它将按预期工作。

This is an old question, but I found it while Googling the same symptoms. Posting this in case someone else finds it for the same reason.

Judah's answer is right, but it isn't the only reason the "unhandled exception in user code" dialog can appear. If an exception is thrown from inside a constructor on the background thread then that exception will cause the dialog immediately, and won't be passed to the RunWorkerCompleted event. If you move the offending code outside of any constructors (to any other method) it works as expected.

燃情 2024-08-01 16:06:31

我遇到了同样的问题,在经过一些谷歌搜索后发现这个主题之前,我已经在应用犹大答案了。

嗯,在我看来,犹大的答案是部分正确的。 我找到了更好的答案 这里

调试器正在使工作顺利进行,如果您在“真实条件”下运行应用程序,RunWorkerCompleted 将按预期处理异常,并且应用程序行为也是预期的。

我希望这个答案有帮助。

I had the same problem and i was already applying the Judah answer before i found this topic after some googling.

Well, imo the Judah answer is partially correct. I found a better answer here

The debugger is making the work well, if you run the application in "real-world conditions", the RunWorkerCompleted deals with the exception as expected and the application behavior is also the expected.

I hope this answer helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文