ThreadExceptionHandler not catching exception in MainFrm constructor - c#

I have a test winforms app with ThreadExceptionHandler that displays a message box when an unhandled exception is caught, as follows:
[STAThread]
static void Main()
{
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show("error caught");
}
When I force an error in the ctor of Form 1 (e.g. dividebyzero) as follows:
public Form1()
{
InitializeComponent();
int i = 0;
int x = 5 / i;
}
and run the app outside of Visual Studio (in Windows 7), the divide by zero exception is not handled - I get an unhelpful "WindowsFormApplication1 has stopped working..." message.
However, when I move the dividebyzero exception to the Form1_Load event and rerun, the exception is handled properly.
Can someone explain why this is the case? The reason I ran this test program is because I am experiencing a similar unhandled exception issue in another, enterprise app that I am trying to track down.

This is probably due to the fact that the constructor is executed before Application.Run() is called. Your code could also be written as
[STAThread]
static void Main()
{
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 MyForm = new Form1();
Application.Run(MyForm);
}
Your thread exception handler only becomes active when Application.Run() is executing. In order to catch exceptions in the form constructor, you need to surround Form1 MyForm = new Form1(); witch a seperate try/catch block.

The error is being thrown in the constructor, not in the threaded code. Your code:
Application.Run(new Form1());
is going to throw the exception right then and there, on that very line of code, before the call to Application.Run(), so the threaded code doesn't even begin executing.

ThreadException handles exceptions UI thread exceptions. UnhandledException handles non-UI thread exceptions.
You need to add this line to your Main():
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
and the following to your class:
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show("error caught 2");
}

Application.ThreadException event is called every time Application throws an exception, however in your example, the exception is thrown in the main thread, you can add a try catch block for it.

Related

how call a function when an exception has occurred and the C# program has stopped?

In a C# program, I want to do some action,when an exception happens; that is when an exception happens and exception window appears, I want to screen capture it and save the image(and other info such as the time and user running the program)of the exception in the db.
Please note that in situation an exception occurs, the program stops until for the user clicks on the button(and if the user clicks on Quit button the app will end).
Your error says Unhandled Exception.
Just put your code in try catch block, and handle it accordingly
try
{
int zero = 0;
double i = (1/zero);
}
catch(Exception ex)
{
//ex contains your error and you can do whatever when you catch it in here
Console.WriteLine("Error: {0}", ex.Message);
}
If you want to catch all unhandled exceptions then you can use the application thread exception method.
In your program.cs you need to register the thread exception, and add a method to do your handling.
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//Register your thread exception method here
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(args));
}
//This method will then be called and you can handle your exception anyway you wish
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
//Add your custom handling code here
}
}

Catch all exception in C# [duplicate]

I have implemented software which have a DLL library which contains a set of classes which includes all the methods for my software.
Now I want to be able to handle some global errors like error #26 which is a no Network Related Error on all these classes instead of going to each class and add it. How should I do that?
If #26 is an exception then you can use AppDomain.CurrentDomain.UnhandledException event. If it's just a return value, then I don't see any chance to handle that globally.
public static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
// start main thread here
}
static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception) args.ExceptionObject;
Console.WriteLine("MyHandler caught : " + e.Message);
}
Since its a winforms app you could just enclose Application.Run(new MainForm()); in a try catch block.
static void Main()
{
try {
Application.Run(new MainForm());
} catch(SystemException)//just as an example
{
//log or handle the error here.
}
}
I don't know any implications this kind of solution would cause, but I just told you what you needed.
Other options are subscribing to Application.ThreadException event.
Read more here: unhandledexceptions
There is also AppDomain.UnhandledException and you should read the difference between them here on MSDN.
From MSDN :
For certain application models, the UnhandledException event can be preempted by other events if the unhandled exception occurs in the main application thread.
In applications that use Windows Forms, unhandled exceptions in the main application thread cause the Application.ThreadException event to be raised. If this event is handled, the default behavior is that the unhandled exception does not terminate the application, although the application is left in an unknown state. In that case, the UnhandledException event is not raised. This behavior can be changed by using the application configuration file, or by using the Application.SetUnhandledExceptionMode method to change the mode to UnhandledExceptionMode.ThrowException before the ThreadException event handler is hooked up. This applies only to the main application thread. The UnhandledException event is raised for unhandled exceptions thrown in other threads.
With the reference of Centralized Exception Handling in C# Windows Application, I found one of good solution :
static class Program
{
[STAThread]
static void Main()
{
// Add handler to handle the exception raised by main threads
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
// Add handler to handle the exception raised by additional threads
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
// Stop the application and all the threads in suspended state.
Environment.Exit(-1);
}
static void Application_ThreadException
(object sender, System.Threading.ThreadExceptionEventArgs e)
{// All exceptions thrown by the main thread are handled over this method
ShowExceptionDetails(e.Exception);
}
static void CurrentDomain_UnhandledException
(object sender, UnhandledExceptionEventArgs e)
{// All exceptions thrown by additional threads are handled in this method
ShowExceptionDetails(e.ExceptionObject as Exception);
// Suspend the current thread for now to stop the exception from throwing.
Thread.CurrentThread.Suspend();
}
static void ShowExceptionDetails(Exception Ex)
{
// Do logging of exception details
MessageBox.Show(Ex.Message, Ex.TargetSite.ToString(),
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
In the above class, we shall attach an event handler to two events. It is better to attach these events as soon as the main method starts.
Application.ThreadException - This event will be raised when an exception is thrown in the main thread. If we add an event handler, then the exception is handled over the method.
AppDomain.CurrentDomain.UnhandledException - This event will be raised when an exception is thrown in the additional threads used in the application. The worse scenario here is as soon as the handlers' execution gets over, the exception is again thrown whereas the application ends. This need to be handled. Here I have used a bit of code to handle this situation and continue the execution of the application without interruption.
The logic I have used to overcome this situation is just suspending the thread in the event handler, so that the application continues to work fine. Again a problem arises in suspending this thread. When the main form is closed, the application normally needs to exit, but as the thread is in suspended state, the application will still remain running. So to exit the application completely and stop the process, Environment.Exit(-1) must be called before the ending of the main method.
First, You should add:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
After that You can catch exceptions, for example:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += ApplicationThreadException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
Application.Run(new MainForm());
}
/// <summary>
/// Global exceptions in Non User Interface (other thread) handler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var message =
String.Format(
"Sorry, something went wrong.\r\n" + "{0}\r\n" + "{1}\r\n" + "Please contact support.",
((Exception)e.ExceptionObject).Message, ((Exception)e.ExceptionObject).StackTrace);
MessageBox.Show(message, #"Unexpected error");
}
/// <summary>
/// Global exceptions in User Interface handler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ApplicationThreadException(object sender, ThreadExceptionEventArgs e)
{
var message =
String.Format(
"Sorry, something went wrong.\r\n" + "{0}\r\n" + "{1}\r\n" + "Please contact support.",
e.Exception.Message, e.Exception.StackTrace);
MessageBox.Show(message, #"Unexpected error");
}
Handle the Application.ThreadException Event.
Global error interception in winforms
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try
{
Application.Run(new myForm());
}
catch (Exception ex)
{
HandleException(ex);
}
}
internal static void HandleException(Exception ex)
{
string LF = Environment.NewLine + Environment.NewLine;
string title = $"Oups... I got a crash at {DateTime.Now}";
string infos = $"Please take a screenshot of this message\n\r\n\r" +
$"Message : {LF}{ex.Message}{LF}" +
$"Source : {LF}{ex.Source}{LF}" +
$"Stack : {LF}{ex.StackTrace}{LF}" +
$"InnerException : {ex.InnerException}";
MessageBox.Show(infos, title, MessageBoxButtons.OK, MessageBoxIcon.Error); // Do logging of exception details
}
}
As an extension of what is shown above, I use the following:
try
{
Application.Run(new FormMain());
}
catch (Exception ex)
{
RoboReporterConstsAndUtils.HandleException(ex);
}
...where the HandleException() method can be something like:
internal static void HandleException(Exception ex)
{
var exDetail = String.Format(ExceptionFormatString,
ex.Message,
Environment.NewLine,
ex.Source,
ex.StackTrace,
ex.InnerException);
ExceptionLoggingService.Instance.LogAndEmailExceptionData(string.Format("{0}: {1}: {2}",
DateTime.Now.ToLongDateString(), GetVersionInfo(), exDetail));
}
Another way to skin this cat is:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AppDomain.CurrentDomain.UnhandledException += Unhandled;
Application.Run(new FormMain());
}
static void Unhandled(object sender, UnhandledExceptionEventArgs exArgs)
{
ExceptionLoggingService.Instance.LogAndEmailMessage(String.Format
("From application-wide exception handler: {0}", exArgs.ExceptionObject));
}
Of course, you can do whatever you want within the Unhandled() method.

How do I get the name of the thread that the exception occurred on?

I am handling thread exceptions but I want to get the name of the Thread that the exception occurred on. It appears that when the thread exception fires the event stays on the main thread although I think the exception could have occurred on a different thread.
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
ShowFaultDialog(e.Exception, "(Application) Thread Exception [" + System.Threading.Thread.CurrentThread.Name + "]");
}
In static void Main():
Thread.CurrentThread.Name = "Main Thread";
VS 2010 shows the main thread as having a 'Name' of "Main Thread" but actually the thread name is null.
If you mean handling of Application.ThreadException event: it fires only on exceptions, that was thrown from WinForms threads. Usually, there's one WinForms thread in application: the main thread.
UPDATE.
Here's sample that demonstrating Application.ThreadException and AppDomain.UnhandledException behavior difference:
1) Program class:
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.Run(new Form1());
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Debug.WriteLine(Thread.CurrentThread.Name);
}
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
Debug.WriteLine(Thread.CurrentThread.Name);
}
}
2) Main form (a form with two buttons) code-behind:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
throw new InvalidOperationException();
}
private void button2_Click(object sender, EventArgs e)
{
new Thread(() => { throw new InvalidOperationException(); })
{
Name = "Worker Thread"
}.Start();
}
}
When you are clicking on button1, you're throwing exception from WinForms thread. So, this exception will be handled at Application_ThreadException by default.
When you are clicking on button2, you're throwing exception from worker thread, which is not a WinForms thread. Application.ThreadException isn't fired in this case, instead AppDomain.UnhandledException event is fired (and CurrentDomain_UnhandledException is called, producing 'Worker Thread' line in output window).
Use an incrememnted numerical variable (such as byte) to give each thread it's own name eg
string threadname = "Thread" + threadnumber
And then use the catch statement to notify you like so:
ShowFaultDialog(e.exception, threadname)
That way you'll be able to tell which thread it is, in theory.
As I understand from MSDN the Application_ThreadException event allows Windows Forms applications to handle unhandled exceptions that occur in Windows Forms threads and when you reach this event you are in your main UI thread. So it will print always the same.
Have you checked the Exception.TargetSite property? This property gives you back the method name and signature where the exception occurred.

How to avoid error message window

we're having an application on server instance and quite rarely, but we have out of memory exception (program is not leaking, just instance is quite small and it operates with quite big amounts of data).
That would be not a problem, as we monitor processes on that server instance and if some of the processes are not found in process list, alert email is sent.
Now the problem is with this:
That prevents process from disappearing from process list, so we don't get alert email about it's failure. Is it possible to disable this message, that if program fails on something we don't catch, it would close without user interaction?
Assuming Windows Forms, I typically do multiple steps to prevent this message box.
First, I connect several handlers in the Main function:
[STAThread]
private static void Main()
{
Application.ThreadException +=
application_ThreadException;
Application.SetUnhandledExceptionMode(
UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException +=
currentDomain_UnhandledException;
Application.Run(new MainForm());
}
Those handlers are being called when an otherwise unhandled exception occurs. I would define them something like:
private static void application_ThreadException(
object sender,
ThreadExceptionEventArgs e)
{
doHandleException(e.Exception);
}
private static void currentDomain_UnhandledException(
object sender,
UnhandledExceptionEventArgs e)
{
doHandleException(e.ExceptionObject as Exception);
}
The actual doHandleException function that is then called does the actual error handling. Usually this is logging the error and notifying the user, giving him the options to continue the application or quit it.
An example from a real-world application looks like:
private static void doHandleException(
Exception e)
{
try
{
Log.Instance.ErrorException(#"Exception.", e);
}
catch (Exception x)
{
Trace.WriteLine(string.Format(
#"Error during exception logging: '{0}'.", x.Message));
}
var form = Form.ActiveForm;
if (form == null)
{
MessageBox.Show(buildMessage(e),
"MyApp", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
MessageBox.Show(form, buildMessage(e),
"MyApp", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
With the helper function:
public static string buildMessage(Exception exception)
{
var result = new StringBuilder();
while (exception != null)
{
result.AppendLine(exception.Message);
result.AppendLine();
exception = exception.InnerException;
}
return result.ToString().Trim();
}
If you are using not Windows Forms but e.g. a Console application or WPF, some handlers are not present, while others are present instead.
The idea stays the same: Subscribe to event handlers that are being called if you have no try...catch around your code blocks.
Personally, I try to have as few of those try...catch blocks as possible (ideally none).
don't know if you can deactivate this - but I think you should not.
Find the bug/problem in your application and handle the problem with a craceful shutdown or by preventing the problem in first case.
Everything else will be a real crude workaround and I don't think your client will be pleased to have such a behavior (after all won't there be data lost? If not this has allways the buggy / not finished touch)
You could put a global try/catch block in your program and exit the program on any unexpected exception.
If using WPF you can try-catch the following two exceptions in your app.xaml.cs. There may be other/complementary exceptions to handle, but this are the two I am usually looking for:
AppDomain.CurrentDomain.UnhandledException - "This event provides notification of uncaught exceptions. It allows the application to log information about the exception before the system default handler reports the exception to the user and terminates the application. If sufficient information about the state of the application is available, other actions may be undertaken — such as saving program data for later recovery. Caution is advised, because program data can become corrupted when exceptions are not handled."
Dispatcher.UnhandledException - "Occurs when a thread exception is thrown and uncaught during execution of a delegate by way of Invoke or BeginInvoke."
ie:
public partial class App : Application
{
public App()
{
this.Dispatcher.UnhandledException += DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
}
private void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// log and close gracefully
}
private new void DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
e.Handled = true;
// log and close gracefully
}
}

ThreadExceptionEventHandler and invoking delegates

If I assign a ThreadExceptionEventHandler to Application.ThreadException, why when I invoke a delegate method using a control on the main application thread are any exceptions thrown by that delegate not triggering the event handler?
i.e.
static void Main()
{
...
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.Run(new Form1());
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
Console.Error.Write("A thread exception occurred!");
}
...
private void Form1_Load(object sender, EventArgs e)
{
Thread syncThread = new Thread(new ThreadStart(this.ThrowException));
syncThread.Start();
}
private void ThrowException()
{
button1.Invoke(new MethodInvoker(delegate
{
// Not handled by ThreadExceptionEventHandler?
throw new Exception();
}));
}
The context on this is that I have a background thread started from a form which is throwing an unhandled exception which terminates the application. I know this thread is going to be unreliable since it is network connectivity reliant and so subject to being terminated at any point, but I'm just interested as to why this scenario doesn't play out as I expect?
Use AppDomain.CurrentDomain.UnhandledException instead , to catch exceptions that occur in threads not created and owned by Windows Forms
You should definetly see MSDN article to clarify this issue

Categories