ThreadExceptionEventHandler and invoking delegates - c#

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

Related

How to capture and handle unhandled exceptions that happens inside Task.Factory

I have coded this inside App startup
inside App.xaml.cs
public App()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
DispatcherUnhandledException += App_DispatcherUnhandledException;
Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(Application_DispatcherUnhandledException);
TaskScheduler.UnobservedTaskException += new EventHandler<UnobservedTaskExceptionEventArgs>(Application_DispatcherUnhandledException2);
this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
}
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
writeMessage(e.Exception);
}
private void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
writeMessage(e.Exception);
}
private static void writeMessage(Exception e)
{
string srMsg = e.InnerException?.Message;
if (srMsg != null)
{
srMsg += "\r\n\r\nStack\r\n" + e.InnerException?.StackTrace;
}
if (srMsg == null)
{
srMsg = e.Message + "\r\n\r\nStack\r\n" + e.StackTrace;
}
srMsg += "\r\n\r\n*********\r\n\r\n";
File.AppendAllText("global_errors.txt", srMsg);
}
private static void Application_DispatcherUnhandledException2(object o, UnobservedTaskExceptionEventArgs e)
{
writeMessage(e.Exception);
}
private static void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
writeMessage(e.Exception);
}
private static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception)args.ExceptionObject;
writeMessage(e);
}
However, this is still not capturing task factory errors
For example
Nothing proposed in this thread works WPF global exception handler
Getting the StackTrace can be done in several ways, it really depends on what fits your needs the best. Anyhow I would suggest you, to try the following.
Add a callback to the AppDomain.FirstChanceException event, at the start of your project e.g. before the errors occur which you want to catch/log. This could look something like the following:
public static Main()
{
AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;
}
private static void CurrentDomain_FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
}
After that, add the Environment.StackTrace in the CurrentDomain_FirstChanceException method. It will hold the current StackTrace as a string. From my testing it includes the FileName and FileLineNumber.
var currentStackTrace = Environment.StackTrace;
// Now it is on to you on what you want to do with the StackTrace. This could be some kind of logging.
Note that this will log ALL exceptions thrown by the AppDomain, no matter if they are handled by the code e.g. try/catch.
The exception is thrown only if you observe the Task by for example calling Wait() or .Result or accessing its Exception property.
Unobserved exceptions are not thrown unless you use the <ThrowUnobservedTaskExceptions> configuration element to revert back to the behavior that was the default in .NET Framework 4 and terminates the process:
<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
If you really want to catch the exception, you should do it in the delegate that you pass to Task.Factory.StartNew. You may wrap this functionality in an extension method as suggested here.

Inner Exception from async thread Owerwrites Outer Exception in .Net [duplicate]

I'm seeing some wierd behaviour when throwing exceptions and catching them in the Application.ThreadException event handler.
Basically whats happening in the sample below is that an exception is thrown in the DoWork event handler of a BackgroundWorker. The RunWorkerCompleted event handler rethrows a new exception with the original as the inner exception.
Why does the inner exception show up in the ThreadException event handler and not the acutal exception being thrown? If I do not provide an inner exception in the RunWorkerCompleted event handler, the correct exception will show up.
using System;
using System.Windows.Forms;
using System.ComponentModel;
namespace WierdExceptionApp
{
class WierdExceptionForm : Form
{
BackgroundWorker worker = new BackgroundWorker();
public WierdExceptionForm()
{
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
throw new Exception("worker_RunWorkerCompleted", e.Error);
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
throw new Exception("worker_DoWork");
}
[STAThread]
static void Main()
{
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.Run(new WierdExceptionForm());
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message);
}
}
}
The RunWorkerCompleted event is marshaled from the BGW thread to the UI thread by the WF plumbing that makes Control.Invoke() work. Essentially, there's a queue with delegates that is emptied by the message loop. The code that does this, Control.InvokeMarshaledCallbacks(), you'll see it on the call stack, has a catch (Exception) clause to catch unhandled exceptions. That clause calls Application.OnThreadException, passing the value of Exception.GetBaseException().
Well, that explains why you only see the inner exception. Why it is done this way is a bit unclear. Possibly to slice off the stack frames of the code in the UI thread that are otherwise pretty confusing since the real exception came from the background thread.
if (e.Error != null)
{
throw new Exception("worker_RunWorkerCompleted", new Exception("Inner", new Exception("Inner inner")));
}
You get "inner inner" at the end. It seems that this is the behavior of Application_ThreadException method to look at the inner-most exception.

Application.ThreadException event for ALL GUI threads

I have a WinForms application that creates a multiple forms, each in their own GUI thread, (not the main GUI thread). I would like to handle the Unhandled Exception event (Application.ThreadException) for all these forms to handle any errors. I would also like to handle exceptions from worker threads - this bit seems to be working correctly, but I'm having trouble with exceptions from GUI threads still:
Program.cs:
[STAThread]
static void Main()
{
AttachExceptionHandlers();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
public static void AttachExceptionHandlers()
{
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Dispatcher.CurrentDispatcher.UnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(CurrentDispatcher_UnhandledException);
}
Form1.cs:
//GUI Thread Crash
private void button1_Click(object sender, EventArgs e)
{
object a = null;
a.ToString();
}
//Worker Thread Crash
private void button2_Click(object sender, EventArgs e)
{
Thread myThread = new Thread(() =>
{
object a = null;
a.ToString();
});
myThread.Start();
myThread.Join();
}
//New Thread, New Gui Crash
private void button3_Click(object sender, EventArgs e)
{
Thread myThread = new Thread(() =>
{
using (CrashingForm form = new CrashingForm()) //Crashing Form Crashes in it's FormLoad event.
{
Application.Run(form);
}
});
myThread.Start();
myThread.Join();
}
This code will call my exception handler in the first 2 instances (GUI Thread Crash and Worker Thread Crash) but does not handle the third instance where a new GUI thread is created. I have found that if I call Program.AttachExceptionHandlers(); before the Application.Run(form) line, all is OK, but this is undesirable as I would have to implement some logic to make sure the call to Program.AttachExceptionHandlers() is made before we call a form is created on each thread (the call to Application.SetUnhandledExceptionMode fails if called after creating a form on the thread).
This example is part of a bigger bit of code which would ideally give the user of my code a simple API to call at the start of their application (like in Program.cs) to attach exception handlers. The exception handler then does some magic to record details about the exception being thrown before the application dies. So telling the user they have to track down each time they create a new GUI thread (worker threads don't seem to be effected by this issue) and reattach the Application.ThreadException Handler is not such a clean solution.
Is there another way to achieve this, without having to re registerer for the Application.ThreadException event each time a new GUI thread is created?
Is there another way to achieve this, without having to re registerer
for the Application.ThreadException event each time a new GUI thread
is created?
I'm not aware of any, and my teammate and I have spent a good amount of time looking into it. .NET WinForms doesn't appear to be very opinionated when it comes to how to create / manage / destroy multiple message pumps.
We use framework methods similar to the one below, in addition to Retlang's WinFormsFiber.
using System;
using System.Threading;
using System.Windows.Forms;
internal static class Program
{
[STAThread]
private static void Main()
{
CreateFormAndStartMessagePump(() => CreateForm("first"), OnException, OnException, false, "pumpThread1");
CreateFormAndStartMessagePump(() => CreateForm("second"), OnException, OnException, false, "pumpThread2");
// note app shutdown not handled here
}
private static T CreateFormAndStartMessagePump<T>(
Func<T> createForm,
ThreadExceptionEventHandler onThreadException,
UnhandledExceptionEventHandler onDomainException,
bool isBackground,
string name) where T : Form
{
var latch = new ManualResetEvent(false);
T form = null;
var thread = new Thread(ts =>
{
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += onThreadException;
AppDomain.CurrentDomain.UnhandledException += onDomainException;
form = createForm();
latch.Set();
Application.Run();
})
{
IsBackground = isBackground,
Name = name
};
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
latch.WaitOne();
return form;
}
private static Form CreateForm(string name)
{
var form = new Form();
form.Text = name;
form.Show();
return form;
}
private static void OnException(object sender, UnhandledExceptionEventArgs e)
{
// ...
}
private static void OnException(object sender, ThreadExceptionEventArgs e)
{
// ...
}
}

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.

ThreadExceptionHandler not catching exception in MainFrm constructor

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.

Categories