Solved
Seems that Oliver is right. After Several tries I got the exception and in debug mode i get it for sure. So this has to be all about timing. You should also check Matthew wattsons answer ;)
Example
First of all a little example that shall explain my confusion.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace testCrossThreading
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
new Thread(ThreadJob).Start();
}
void ThreadJob()
{
//label1.Text = "1";
changeText(label1, "1");
}
void changeText(Label L, String message)
{
L.Text = message;
}
}
}
Question
So now my question: if I uncomment label1.Text = "1"; in the function "ThreadJob" then I get an Cross thread exception as expected.
But if i leave it commented like the example shows it does work. But why?
The function is called by the sub thread and I don't invoke anything. So it is still the sub Thread and not the GUI thread that changes the text of label imo. Or am I missing something?
I would write it like this.
void ThreadJob()
{
Action a = () => label1.Text = "1";
this.Invoke(a);
}
I think it's just a timing issue. If you try to update a gui element from a non-gui thread the cross-thread exception can be thrown. You can even disable the whole cross-thread exceptions by calling
Form.CheckForIllegalCrossThreadCalls = false;
but after the exception is gone, the further behavior is undefined and can lead to very subtle bugs. So take the exception as a hint for a code smell but be aware that sometimes the exception won't be thrown even if it should be.
I think you may have a race condition, which is why results are varying.
If you attempt to change the Text property of a control which isn't currently displayed, then .Net doesn't care which thread changes it.
In your code, you start a thread from the constructor. The code which actually displays the form may or may not have displayed it before the code in the thread that sets the property executes.
When you call an extra function to set the property, the timings change and exposes the race condition.
You could test this by adding a Thread.Sleep(100) to the start of ThreadJob().
Related
Very similar problem to Selenium C#: Actions class works during debug mode but does not work during regular test run, but the OP of that question seemingly never got an answer that actually works.
My code:
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Interactions;
using System;
using System.Linq;
namespace IMPPACT.UI.FunctionalTest.RiskManagement {
public class MyTestClass : ChromeTestBase {
[Test]
public void MyTestMethod() {
// ...several lines of initial setup code, definitely working
var action = new Actions(driver);
// categoriesMultiSelect is an IWebElement object that is associated with a
// Kendo UI MultiSelect control that is definitely interactable at this point
action.MoveToElement(categoriesMultiSelect).Build().Perform();
action.MoveByOffset(0, -30).Build().Perform();
action.Click();
// ...more code that interacts with elements that are
// hidden by categoriesMultiSelect when it is open
}
}
}
As reported by the OP of the question linked above, this works fine when stepping through the code in debug mode (or even if I run past the shown block in one fell swoop), but fails when running the test normally.
I've also tried:
action.MoveToElement(categoriesMultiSelect).MoveByOffset(0, -30).Click().Build().Perform();
Instead of splitting it into three lines, but to no avail :-( Any suggestions re: what I'm doing wrong would be greatly appreciated.
Recently, I was running into a problem which I'm still breaking my head over. In an application, I registered a dispatcher exception handler. In the same application, a third-party-component (DevExpress Grid Control) causes an exception within the event handler for Control.LayoutUpdated. I expect, that the dispatcher exception handler is triggered once. But instead, I get a stack overflow. I produced a sample without the third party component and discovered, that it happens in every WPF application.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
namespace MyApplication
{
/* App.xaml
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MyApplication.App"
Startup="OnStartup"
/>
*/
public partial class App
{
private void OnStartup(object sender, StartupEventArgs e)
{
DispatcherUnhandledException += OnDispatcherUnhandledException;
MainWindow = new MainWindow();
MainWindow.Show();
}
private static void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message);
e.Handled = true;
}
}
public class MainWindow : Window
{
private readonly Control mControl;
public MainWindow()
{
var grid = new Grid();
var button = new Button();
button.Content = "Crash!";
button.HorizontalAlignment = HorizontalAlignment.Center;
button.VerticalAlignment = VerticalAlignment.Center;
button.Click += OnButtonClick;
mControl = new Control();
grid.Children.Add(mControl);
grid.Children.Add(button);
Content = grid;
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
mControl.LayoutUpdated += ThrowException;
mControl.UpdateLayout();
mControl.LayoutUpdated -= ThrowException;
}
private void ThrowException(object sender, EventArgs e)
{
throw new NotSupportedException();
}
}
}
Is there any way to prevent this behavior? It happens with .NET framework 3.0, 3.5, 4.0 and 4.5. I can't just wrap a try-catch around the LayoutUpdated event handler since it is in a third party component and I don't think, a stack overflow should happen.
I think Florian GI is right about the message box, but if instead of a message box you did something else (or nothing i.e. just set Handled to true) in the OnDispatcherUnhandledException method it still loops forever and doesn't get to the mControl.LayoutUpdated -= ThrowException; line.
So I thought I would have a little snop through the code with dotPeek...
When you call UpdateLayout on the control, ultimately it gets to the method ContextLayoutManager.UpdateLayout and a snippet of this method looks like this:
// ... some code I snipped
bool flag2 = true;
UIElement element = (UIElement) null;
try
{
this.invalidateTreeIfRecovering();
while (this.hasDirtiness || this._firePostLayoutEvents)
{
//... Loads of code that I think will make sure
// hasDirtiness is false (since there is no reason
// for anything remaining dirty - also the event is
// raised so I think this is a safe assumption
if (!this.hasDirtiness)
{
this.fireLayoutUpdateEvent();
if (!this.hasDirtiness)
{
this.fireAutomationEvents();
if (!this.hasDirtiness)
this.fireSizeChangedEvents();
}
}
//... a bit more
flag2 = false;
}
}
finally
{
this._isUpdating = false;
this._layoutRequestPosted = false;
//... some more code
if (flag2)
{
//... some code that I can't be bothered to grok
this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Delegate) ContextLayoutManager._updateLayoutBackground, (object) this);
}
}
// ... and for good measure a smidge more code
I'm going to take a punt and suggest that the _firePostLayoutEvents flag is true in your case.
The only place where _firePostLayoutEvents is set to false is in the fireAutomationEvents method so let's assume that somewhere before the end of the fireAutomationEvents method your exception is thrown (I would guess the fireLayoutUpdateEvent method) so this flag will not get set to false.
But, of course, the finally is outside the loop so it will not loop forever (and if it did you'd not get a StackOverflowException).
Right, onward, so we are invoking the UpdateLayoutBackground function, which actually just calls NeedsRecalc so let's look at that...
private void NeedsRecalc()
{
if (this._layoutRequestPosted || this._isUpdating)
return;
MediaContext.From(this.Dispatcher).BeginInvokeOnRender(ContextLayoutManager._updateCallback, (object) this);
this._layoutRequestPosted = true;
}
Rightyho, that is calling the UpdateLayoutCallback so squinting at that...
private static object UpdateLayoutCallback(object arg)
{
ContextLayoutManager contextLayoutManager = arg as ContextLayoutManager;
if (contextLayoutManager != null)
contextLayoutManager.UpdateLayout();
return (object) null;
}
Oooooh, that is interesting - it's calling UpdateLayout again - I would, therefore, hazzard a slightly educated guess that that is the root cause of your problem.
Therefore, I don't think there is anything much you can do about it I am afraid.
I am not quite sure about the following, but maybe it's a guess in the right direction.
In MSDN it sais:
However, LayoutUpdated can also occur at run time during the object
lifetime, for a variety of reasons: a property change, a window
resizing, or an explicit request (UpdateLayout or ApplyTemplate).
So it might get also fired after a MessageBox has shown?
If thats the case a MessageBox would open through an unhandled exception, which fires the LayoutUpdated-EventHandler and this again raises an unhandled exception. This would lead to an endless loop and after a while to the stack overflow.
If you do not throw an unhandled exception in the LayoutUpdated-EventHandler, but call the MessageBox.Show()-method it also ends in an endless loop, what would proof my point.
I realize I'm over four years late to the party, but maybe someone will find this useful...
Your application's dispatcher does not stop responding to input and layout events during the call to MessageBox.Show(). The LayoutUpdated event fires any time there is any layout-related work to do, which happens far more often than you might expect. It will continue to fire while the message box is displayed, and if whatever condition triggered the error continues to persist, new exceptions will be raised, and your handler will show more and more message boxes. And because MessageBox.Show() is a blocking call, it's not going to disappear from the call stack until it returns. Subsequent invocations of your handler will be pushed deeper and deeper into the dispatcher's call stack until it overflows.
You really have two separate problems:
Your code to display a crash dialog is reentrant.
Your application continues to raise exceptions on the dispatcher thread while your crash dialog is being displayed.
You could solve the first issue with a non-reentrant queue. Rather than displaying the crash dialog immediately, have your handler place the exception in a queue. Have your handler process the queue only if you are not already processing it farther up the stack. This prevents multiple crash dialogs from being shown simultaneously, and should keep your call stack from growing too deep, thus avoiding your stack overflow issue.
To address the second problem, you should probably shut down the offending part of your application as soon as you see the first exception (and before you show the crash dialog). Alternatively, you could devise a way to filter out duplicate exceptions and ensure that equivalent errors don't end up in the queue at the same time. But given how rapidly the exceptions are recurring, I would choose the first option.
Keep in mind that you need to address both of these issues. If you don't address the second issue, you'll likely end up trading in your StackOverflowException for an OutOfMemoryException. Or you'll show an infinite number of crash dialogs, one after the other. Either way, it'll be bad.
I wonder how can I write a catch'em all exception handler in the application level which will give the user the option to resume the application flow?
If you are running a Windows Forms application: add a handler to the Application.ThreadException event.
I assume you are writing a Windows application in which case, yes, you can do this. I will leave the rights and wrongs of whether or not you should to others. There are already enough answers which look at this and I suggest you consider them carefully before you actually do this.
Note, that this code will behave differently in the debugger than it does if you run the application directly (another reason not to do it perhaps). To get the application to show the messagebox and to continue on thereafter you will need to run the application from explorer, not from visual studio.
Create a new Windows forms application. The code in Program.cs looks something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication2 {
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 form1 = new Form1();
Application.ThreadException += new ThreadExceptionEventHandler(form1.UnhandledThreadExceptionHandler);
Application.Run(form1);
}
}
}
Then make the code in Form1 look something like this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication2 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
public void UnhandledThreadExceptionHandler(object sender, ThreadExceptionEventArgs e) {
this.HandleUnhandledException(e.Exception);
}
public void HandleUnhandledException(Exception e) {
// do what you want here.
if (MessageBox.Show("An unexpected error has occurred. Continue?",
"My application", MessageBoxButtons.YesNo, MessageBoxIcon.Stop,
MessageBoxDefaultButton.Button2) == DialogResult.No) {
Application.Exit();
}
}
private void button1_Click(object sender, EventArgs e) {
throw new ApplicationException("Exception");
}
}
}
(Add button1 to the form and attach it button1_Click.)
It depends on what you mean by "resume". The trouble with exceptions is that unless you're very careful, by the time an exception happens your application state is quite possibly corrupt - you might have completed half an operation.
If you can isolate your operations - much like a database isolates transactions - then you can effectively let your user resume from the "last commit point". That will very much depend on the type of your application though. Could you give us more details about the kind of application you're building?
Use below code in your program.cs class. It will automatically Send mail when exception occurs.
using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Mail;
using System.Threading;
namespace ExceptionHandlerTest
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.ThreadException +=
new ThreadExceptionEventHandler(Application_ThreadException);
// Your designer generated commands.
}
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
var fromAddress = new MailAddress("your Gmail address", "Your name");
var toAddress = new MailAddress("email address where you want to receive reports", "Your name");
const string fromPassword = "your password";
const string subject = "exception report";
Exception exception = e.Exception;
string body = exception.Message + "\n" + exception.Data + "\n" + exception.StackTrace + "\n" + exception.Source;
var smtp = new SmtpClient
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(fromAddress.Address, fromPassword)
};
using (var message = new MailMessage(fromAddress, toAddress)
{
Subject = subject,
Body = body
})
{
//You can also use SendAsync method instead of Send so your application begin invoking instead of waiting for send mail to complete. SendAsync(MailMessage, Object) :- Sends the specified e-mail message to an SMTP server for delivery. This method does not block the calling thread and allows the caller to pass an object to the method that is invoked when the operation completes.
smtp.Send(message);
}
}
}
}
I don't think this is really feasible using a global error handler. You need to figure out what kind of errors are recoverable at different points in your application and write specific error handlers to address the errors as they occur -- unless you want to resort to application restart, which may or may not work depending on what the actual error is. In order to do any kind of resume, you'll need to save enough state to restart from a known good state.
You should read up on all the problems associated with VB's "On Error Resume Next" style of error handling. It sounds like you're trying to implement this for C#.
Even if you can resume from the point of where the exception is generated, this is a broken technique for error handling. There's no way for a global handler to actually be able to handle any error/exception - it can't possibly know what's required for any arbitrary situation.
You would have to set some sort of global variable, and have the mainline code continually check it for error indications (ie., use the VB technique).
I think the best you can do to recover from an error like you're describing is to catch the exception at the application level, log the problem, inform the user (and potentially generate/send some sort of problem report for you), and restart the application. Of course, if you catch the exception closer to the problem area, that handler has a chance to do something a bit more intelligent, so you should not rely on the app-level handler as a crutch - just as a fail-safe.
In some versions of .NET you can actually put a catcher around the Application.Run() (you'll find this in program.cs) and this should catch all the Main Thread's exceptions however in most cases this maybe poor design and wont give you much of an opportunity to "resume".
Additionally you will always have to manually handle any exceptions on background threads.
You can design an app to "catch all" and display a common error message and debug info, this is fine as long as you exit afterwards. What is highly discouraged is making a "resume" available to the user as this will probably give you more problems in the long-run.
This just screams bad design all over. Never use exceptions for things like this. Exceptions are ONLY to be used when something the programmer did not intend to occures.
If you want error-handling. dont use exceptions like this, rahter build a system where you save states and can go back to states etc... but using exceptions for state handling, bad idea.
Microsoft Enterprise Library Exception Handling Application Block has examples of how you can do this.
Basically you surround the code that can throw exceptions with this:
try
{
MyMethodThatMightThrow();
}
catch(Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "SomePolicy");
if (rethrow) throw;
}
Then you can configure the Policy to show a dialog to the user and ask if she wants to continue.
You still need to put try catch blocks around in your code at points where you believe you are at a consistent state.
I'm getting a NullReferenceException error on some simple code for handling a button click event. I've still got just a bit of code to add at the very end to actually display the value from "TcpAddr" on the messagebox. This will allow you run the program but clicking the button causes it to throw the error.
Also: Is it better practice to move the actual query out of the click event and just make the click event handle MessageBox.Show()?
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;
namespace LiteSwitch
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
RegistryKey RegKey = Registry.LocalMachine;
RegKey = RegKey.OpenSubKey("SOFTWARE\\Altiris\\Client Service");
object CurrDS = RegKey.GetValue("TcpAddr"); //This line causes the NRE Error
MessageBox.Show("Current DS:");
}
}
}
If you are sure that the registry key actually exists (use Regedit.exe) then you've got a problem if you are running on the 64-bit version of Windows. A VS2010 project is forced to run in 32-bit mode by default, it sees another set of registry keys.
Project + Properties, Build tab, Platform Target = Any CPU. Repeat for the Release configuration.
My guess is that
RegKey = RegKey.OpenSubKey("SOFTWARE\\Altiris\\Client Service");
Is returning a null, probably because that key doesn't exist.
Verify the key exists and the provided reg path is correct.
According to the documentation for OpenSubKey(), "If the specified subkey cannot be found, then null is returned." If a variable is null, calling a method on it will throw that exception.
"Is it better practice to move the actual query out of the click event and just make the click event handle MessageBox.Show()?"
If you take it out, it won't necessarily reflect the current value of the key if, for example, another program modifies it while your program is running. Depending on your program, this may be okay.
If it's throwing a NRE it's because it can't find the value, make sure it's spelled correctly or that the previous line isn't also returning null.
I wonder how can I write a catch'em all exception handler in the application level which will give the user the option to resume the application flow?
If you are running a Windows Forms application: add a handler to the Application.ThreadException event.
I assume you are writing a Windows application in which case, yes, you can do this. I will leave the rights and wrongs of whether or not you should to others. There are already enough answers which look at this and I suggest you consider them carefully before you actually do this.
Note, that this code will behave differently in the debugger than it does if you run the application directly (another reason not to do it perhaps). To get the application to show the messagebox and to continue on thereafter you will need to run the application from explorer, not from visual studio.
Create a new Windows forms application. The code in Program.cs looks something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication2 {
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 form1 = new Form1();
Application.ThreadException += new ThreadExceptionEventHandler(form1.UnhandledThreadExceptionHandler);
Application.Run(form1);
}
}
}
Then make the code in Form1 look something like this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication2 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
public void UnhandledThreadExceptionHandler(object sender, ThreadExceptionEventArgs e) {
this.HandleUnhandledException(e.Exception);
}
public void HandleUnhandledException(Exception e) {
// do what you want here.
if (MessageBox.Show("An unexpected error has occurred. Continue?",
"My application", MessageBoxButtons.YesNo, MessageBoxIcon.Stop,
MessageBoxDefaultButton.Button2) == DialogResult.No) {
Application.Exit();
}
}
private void button1_Click(object sender, EventArgs e) {
throw new ApplicationException("Exception");
}
}
}
(Add button1 to the form and attach it button1_Click.)
It depends on what you mean by "resume". The trouble with exceptions is that unless you're very careful, by the time an exception happens your application state is quite possibly corrupt - you might have completed half an operation.
If you can isolate your operations - much like a database isolates transactions - then you can effectively let your user resume from the "last commit point". That will very much depend on the type of your application though. Could you give us more details about the kind of application you're building?
Use below code in your program.cs class. It will automatically Send mail when exception occurs.
using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Mail;
using System.Threading;
namespace ExceptionHandlerTest
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.ThreadException +=
new ThreadExceptionEventHandler(Application_ThreadException);
// Your designer generated commands.
}
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
var fromAddress = new MailAddress("your Gmail address", "Your name");
var toAddress = new MailAddress("email address where you want to receive reports", "Your name");
const string fromPassword = "your password";
const string subject = "exception report";
Exception exception = e.Exception;
string body = exception.Message + "\n" + exception.Data + "\n" + exception.StackTrace + "\n" + exception.Source;
var smtp = new SmtpClient
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(fromAddress.Address, fromPassword)
};
using (var message = new MailMessage(fromAddress, toAddress)
{
Subject = subject,
Body = body
})
{
//You can also use SendAsync method instead of Send so your application begin invoking instead of waiting for send mail to complete. SendAsync(MailMessage, Object) :- Sends the specified e-mail message to an SMTP server for delivery. This method does not block the calling thread and allows the caller to pass an object to the method that is invoked when the operation completes.
smtp.Send(message);
}
}
}
}
I don't think this is really feasible using a global error handler. You need to figure out what kind of errors are recoverable at different points in your application and write specific error handlers to address the errors as they occur -- unless you want to resort to application restart, which may or may not work depending on what the actual error is. In order to do any kind of resume, you'll need to save enough state to restart from a known good state.
You should read up on all the problems associated with VB's "On Error Resume Next" style of error handling. It sounds like you're trying to implement this for C#.
Even if you can resume from the point of where the exception is generated, this is a broken technique for error handling. There's no way for a global handler to actually be able to handle any error/exception - it can't possibly know what's required for any arbitrary situation.
You would have to set some sort of global variable, and have the mainline code continually check it for error indications (ie., use the VB technique).
I think the best you can do to recover from an error like you're describing is to catch the exception at the application level, log the problem, inform the user (and potentially generate/send some sort of problem report for you), and restart the application. Of course, if you catch the exception closer to the problem area, that handler has a chance to do something a bit more intelligent, so you should not rely on the app-level handler as a crutch - just as a fail-safe.
In some versions of .NET you can actually put a catcher around the Application.Run() (you'll find this in program.cs) and this should catch all the Main Thread's exceptions however in most cases this maybe poor design and wont give you much of an opportunity to "resume".
Additionally you will always have to manually handle any exceptions on background threads.
You can design an app to "catch all" and display a common error message and debug info, this is fine as long as you exit afterwards. What is highly discouraged is making a "resume" available to the user as this will probably give you more problems in the long-run.
This just screams bad design all over. Never use exceptions for things like this. Exceptions are ONLY to be used when something the programmer did not intend to occures.
If you want error-handling. dont use exceptions like this, rahter build a system where you save states and can go back to states etc... but using exceptions for state handling, bad idea.
Microsoft Enterprise Library Exception Handling Application Block has examples of how you can do this.
Basically you surround the code that can throw exceptions with this:
try
{
MyMethodThatMightThrow();
}
catch(Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "SomePolicy");
if (rethrow) throw;
}
Then you can configure the Policy to show a dialog to the user and ask if she wants to continue.
You still need to put try catch blocks around in your code at points where you believe you are at a consistent state.