C# Winforms handle unhandled exceptions - c#

I want to catch all unhandled exceptions in my application. so I used this code to catch all the unhandled exceptions:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
SaveEx(e.Exception);
Application.Exit();
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
SaveEx((Exception)e.ExceptionObject);
Application.Exit();
}
static void SaveEx(Exception ex)
{
bool exists = System.IO.Directory.Exists(Path.GetDirectoryName(#"C:\AppLogs\"));
if (!exists)
System.IO.Directory.CreateDirectory(Path.GetDirectoryName(#"C:\AppLogs\"));
String filePath = #"C:\AppLogs\" + DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss") + ".txt";
String log = "===========Start=============\r\n";
log += "Error Message: " + ex.Message + "\r\n";
log += "Stack Trace: " + ex.StackTrace + "\r\n";
log += "===========End=============";
System.IO.File.WriteAllText(filePath, log);
}
}
I tried to raise these exceptions with a divide in 0:
on main thread it's work perfect:
int t = 0;
int r = 5 / t;
But when i try to do it inside a Thread:
Thread thread = new Thread(delegate()
{
int t = 0;
int r = 5 / t;
});
thread.Start();
The CurrentDomain_UnhandledException function got called but it keeps calling the int r = 5 / t; row in my code so I have a loop of exceptions. Any idea what can be the problem? the thread is called only once.

You need to change Application UnhandledExceptionMode
to UnhandledExceptionMode.CatchException to make things works correctly. Microsoft already wrote a very good article about it here.
I tried to simulate your work. Everything worked well, take a look on my example.
[STAThread]
static void Main()
{
// Set the unhandled exception mode to force all Windows Forms errors to go through
// our handler.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Add the event handler for handling UI thread exceptions to the event.
Application.ThreadException += Application_ThreadException;
// Add the event handler for handling non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message, "Application_ThreadException");
Application.Exit();
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var exception = e.ExceptionObject as Exception;
MessageBox.Show(exception.Message, "CurrentDomain_UnhandledException");
Application.Exit();
}
So, if we raise an exception inside a thread like below:
private void button1_Click(object sender, EventArgs e)
{
var thread = new Thread(delegate () {
throw new DivideByZeroException();
});
thread.Start();
}
button1_Click is fired.
thread get started and raises a DividedByZeroException.
CurrentDomain_UnhandledException catches the exception, shows the message and closes the app

Related

C# Global exception handler

This question has been answered a thousand times but although I've tried everything, I can't seem to get my Global Exception Handler to work.
I'm using a windows form with several async methods. All my async methods are wrapped in try catch blocks and handled accordingly. I also have every block of code where I expect an exception wrapped in a try catchblock.
I'm interested in using a global exception handler to catch exceptions that I'm not expecting so that I can log them and let the user know there has been an exception before safely closing down the program.
In Main() I have the following:
[STAThread]
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
static void Main()
{
crashLogInit = InitLogExceptions(); // sets global exception handlers and returns true if successful.
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainWindow = new MainWindow(); // My window
LoadSaveManager.Init(); // initiates all relavent components for saving and loading data.
if (isLoaded() && crashLogInit) // Loads data and checks it is successful, also checks global exception handlers are set.
{
RunProgram(); //Method which does Application.Run(MainWindow);
}
else
{
MessageBox.Show(Form.ActiveForm, "Error while starting application!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
CloseResources();
}
}
In the InitLogExceptions() I have the following:
private static bool InitLogExceptions()
{
try
{
crashlogPath = Path.Combine(Directory.GetCurrentDirectory(), crashlogName);
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
return true;
}
catch { return false; }
}
In MainWindow() I have a button which fires a clicked event which throws an ArgumentNullException which is getting caught by the debbugers own exception handler but isnt getting caught by any of mine nor is it getting logged.
Below is the code for my exception handlers:
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
ShowException(sender, e.Exception, true);
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
ShowException(sender, e.ExceptionObject as Exception, true);
}
public static void ApplicationHandler(object sender, Exception e)
{
if (!crashLogInit) { InitLogExceptions(); }
ShowException(sender, e, false);
}
public static void ApplicationHandler(object sender, Exception e, bool forceClose)
{
if (!crashLogInit) { InitLogExceptions(); }
ShowException(sender, e, forceClose);
}
private static bool WriteToLog(object sender, Exception exception)
{
try
{
DateTime dateTime = DateTime.Now;
StreamWriter writer = File.AppendText(crashlogPath);
string date = dateTime.ToString("yyyy-MM-dd # HH:mm:ss");
writer.WriteLine(date + ":");
writer.WriteLine();
writer.WriteLine();
writer.Write($" SENDER: {sender.GetType().ToString()} EXCEPTION MESSAGE: {exception.Message}");
writer.WriteLine(exception.Source == null ? "" : $"SOURCE: {exception.Source}");
writer.WriteLine();
writer.WriteLine(exception.StackTrace == null ? exception.InnerException.StackTrace : exception.StackTrace);
if (exception.GetType().IsSubclassOf(typeof(AppExceptions)))
{
writer.WriteLine();
writer.WriteLine($"ORIGINAL MESSAGE: {exception.InnerException.Message} ORIGINAL SOURCE: {exception.InnerException.Source}");
}
writer.WriteLine();
writer.WriteLine();
writer.Close();
return true;
}
catch (Exception)
{
return false;
}
}
private static void ShowException(object sender, Exception e, bool forceClose)
{
StringBuilder output = new StringBuilder();
if (WriteToLog(sender, e))
{
output.AppendLine($"Copied to Crashlog! Location of Crashlog file: {crashlogPath}");
output.AppendLine();
output.AppendLine("Send Crashlog to developer!");
}
else
{
output.AppendLine("Could not copy to Crashlog!");
}
output.AppendLine();
output.AppendLine(forceClose ? "Application will now close!" : "Application will now continue at user's own risk!");
MessageBox.Show(Form.ActiveForm, output.ToString(), e.Message.ToUpper() + "!", MessageBoxButtons.OK, MessageBoxIcon.Error);
if (forceClose)
{
Environment.FailFast(e.Message, e);
}
}
Exceptions else where are working and getting logged except this simple thrown exception on a button clicked. What am I doing wrong?

Updating status strip label async/await

I have a WinForm, with a toolStripStatusLabel. There is a button, which spawns a new thread to perform its task. The status label needs to update during, and after this task is completed. The GUI elements are in the main thread. If I want to achieve this, can I place the relevant lines to update the label where the comments are below in the code snippet below? Also, I need to have another form open when this label is clicked. From my understanding of asynchronous coding, this should be straightforward, involving an event handler for the label, and the fact that control will return to the caller of the async method. Is this correct? I am relatively new to multithreaded and asynchronous programming, so I am quite confused.
// this is running in the main GUI thread
private async void Export_execute_Click(object sender, System.EventArgs args)
{
try
{
await System.Threading.Tasks.Task.Run(() => do_export(filename, classes, System.TimeZoneInfo.ConvertTimeToUtc(timestamp)));
// if this is successful, status label should be update (task successful)
}
catch (System.Exception e)
{
// status label should be updated (task failed)
}
}
If there is something literally awaitable in the Export method then I think to make it an async method would be better.
private async void Export_execute_Click(object sender, EventArgs e)
{
try
{
await ExportAsync("file1", "classA", DateTime.Now);
toolStripStatusLabel.Text = $"Export finished at {DateTime.Now}";
}
catch (Exception ex)
{
toolStripStatusLabel.Text = $"Export failed, {ex.ToString()}";
}
}
private async Task ExportAsync(string fileName, string classes, DateTime timestamp)
{
toolStripStatusLabel.Text = $"Export start at {timestamp}";
await Task.Delay(TimeSpan.FromSeconds(5));
toolStripStatusLabel.Text = $"Have first half done {timestamp}";
await Task.Delay(TimeSpan.FromSeconds(5));
}
private void toolStripStatusLabel_Click(object sender, EventArgs e)
{
Form2 frm2 = new Form2();
frm2.Show();
}
The standard way to report progress is to use the IProgress<T> interface. There is already an implementation of this interface that you can use (Progress<T>), and is generic so that you can supply any type of argument you want. In the example bellow the argument is a string. The key point is that the event Progress.ProgressChanged is running in the UI thread, so you don't have to worry about it.
// This will run in the UI thread
private async void Export_Execute_Click(object sender, EventArgs args)
{
try
{
var progress = new Progress<string>();
progress.ProgressChanged += ExportProgress_ProgressChanged;
// Task.Factory.StartNew allows to set advanced options
await Task.Factory.StartNew(() => Do_Export(filename, classes,
TimeZoneInfo.ConvertTimeToUtc(timestamp), progress),
CancellationToken.None, TaskCreationOptions.LongRunning,
TaskScheduler.Default);
toolStripStatusLabel.Text = $"Export completed successfully";
}
catch (Exception e)
{
toolStripStatusLabel.Text = $"Export failed: {e.Message}";
}
}
// This will run in the UI thread
private void ExportProgress_ProgressChanged(object sender, string e)
{
toolStripStatusLabel.Text = e;
}
// This will run in a dedicated background thread
private void Do_Export(string filename, string classes, DateTime timestamp,
IProgress<string> progress)
{
for (int i = 0; i < 100; i += 10)
{
progress?.Report($"Export {i}% percent done");
Thread.Sleep(1000);
}
}
How about a BackgroundWorker instead of your current Task? I prefer these because they allow easy communication between the main thread and the worker.
Note that Export_execute_Click is no longer marked as async in this scenario.
Example:
private void Export_execute_Click(object sender, System.EventArgs args) {
// Method level objects are accessible throughout this process
bool error = false;
// Process
BackgroundWorker worker = new BackgroundWorker {
WorkerReportsProgress = true
};
// This executes on main thread when a progress is reported
worker.ProgressChanged += (e, ea) => {
if (ea.UserState != null) {
// ea.UserState.ToString() contains the string progress message
}
};
// This executes as an async method on a background thread
worker.DoWork += (o, ea) => {
try {
var response = do_export(filename, classes, System.TimeZoneInfo.ConvertTimeToUtc(timestamp)));
if (response == whatever) {
worker.ReportProgress(0, "Response from do_export() was `whatever`");
} else {
worker.ReportProgress(0, "Response from do_export() was something bad");
error = true;
}
} catch (System.Exception e) {
worker.ReportProgress(0, $"do_export() failed: {e}");
}
};
// This executes on the main thread once the background worker has finished
worker.RunWorkerCompleted += async (o, ea) => {
// You can communicate with your UI normally again here
if (error) {
// You had an error -- the exception in DoWork() fired
} else {
// You're all set
}
// If you have a busy-indicator, here is the place to disable it
// ...
};
// I like to set a busy-indicator here, some sort of ajax-spinner type overlay in the main UI, indicating that the process is happening
// ...
// This executes the background worker, as outlined above
worker.RunWorkerAsync();
}

unhandledexception C#

I have this piece of code, I'm using a timer to call my RunTest() function. If I don't use timer, all the unhandled exception inside RunTest() are caught, but with this timer code they are not getting caught. What mistake am I making?
private static TelemetryClient telemetryClient = new TelemetryClient();
private static System.Timers.Timer aTimer;
static void Main(string[] args)
{
// Register Unhandled Exception Handler
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
// Set the Instrumentation Key to track the WebJob Exception
TelemetryConfiguration.Active.InstrumentationKey = SecureConfigReader.GetSetting("ApplicationInsightsKey");
Configure();
if (args.Length > 0)
{
// Create a timer with a ten second interval.
aTimer = new System.Timers.Timer(10000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
double Scheduled_Interval = Convert.ToDouble(args[0]);
// Set the Interval to 300 seconds.
aTimer.Interval = TimeSpan.FromSeconds(Scheduled_Interval).TotalMilliseconds;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
}
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
RunTests();
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
ExceptionTelemetry excTelemetry = new ExceptionTelemetry((Exception)e.ExceptionObject);
excTelemetry.SeverityLevel = SeverityLevel.Critical;
excTelemetry.HandledAt = ExceptionHandledAt.Unhandled;
telemetryClient.InstrumentationKey = SecureConfigReader.GetSetting("ApplicationInsightsKey");
telemetryClient.TrackException(excTelemetry);
//make sure all telemetry is sent before closing the app
telemetryClient.Flush();
}
/*
* 1. Find all tests
* 2. Run all tests, collecting all results
* 3. Process alerts if any
* 4. Save results
*/
private static void RunTests()
{
List<SyntheticTransactionTableEntity> results = new List<SyntheticTransactionTableEntity>();
List<ISyntheticTransaction> tests = new List<ISyntheticTransaction>();
}
Its documented that:
The Timer component catches and suppresses all exceptions thrown by
event handlers for the Elapsed event.
You need to catch within the OnTimedEvent method and then propagate that exception back out e.g by throwing it on another thread if you want CurrentDomain_UnhandledException to catch it (throw in ThreadPool.QueueUserWorkItem())
Alternatively create a handler:
private static void TimerExceptionHandler(Exception ex)
{
Console.WriteLine(ex.ToString());
...
}
Pass it to the ElapsedEventHandler:
aTimer.Elapsed += (sender, e) => { OnTimedEvent(sender, e, TimerExceptionHandler); };
Call it when an exception is thrown:
private static void OnTimedEvent(object source, ElapsedEventArgs e, Action<Exception> timerExceptionHandler)
try
{
RunTests();
}
catch (Exception ex)
{
timerExceptionHandler(ex);
}

Exception thrown in onEnter - Not caught by main loop

I have this code:
try
{
Application.Run(myForm);
}
catch (Exception e)
{
// handle
}
In my MyForm, when I throw an exception in a button click handler, it is caught as expected and handled by the above code. When I throw in the form's onEnter handler, it is not caught.
Use AppDomain.CurrentDomain.UnhandledException
public static void Main()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
Application.Run(myForm);
}
static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception) args.ExceptionObject;
Console.WriteLine("MyHandler caught : " + e.Message);
Console.WriteLine("Runtime terminating: {0}", args.IsTerminating);
}

Log unhandled exception

I have been trying to log this exception for days but cant figure it out. So I thought I post it here with the hope that someone could help. I have also posted some of my code that I'm currently using to catch unhandled exceptions but the exception never showed up in the log file.
I would appreciate if someone could help me.
Problem Event Name: APPCRASH
Application Name: Myapp.exe
Application Version: 1.0.0.0
Application Timestamp: 52e9aab8
Fault Module Name: clr.dll
Fault Module Version: 4.0.30319.18052
Fault Module Timestamp: 5173c26b
Exception Code: c00000fd
Exception Offset: 00372b52
OS Version: 6.1.7601.2.1.0.272.7
Locale ID: 1033
Additional Information 1: 5cff
Additional Information 2: 5cfff2c5825852a6f100872ec6f038a2
Additional Information 3: a2a3
Additional Information 4: a2a3734c473189c5efabc88b5081d05a
public MainWindow()
{
Application.Current.DispatcherUnhandledException += CurrentOnDispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
Dispatcher.UnhandledException += DispatcherOnUnhandledException;
InitializeComponent();
}
private void DispatcherOnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs args)
{
Exception e = (Exception)args.Exception;
using (StreamWriter writer = File.AppendText("ExceptionsLog.txt"))
{
DateTime time = DateTime.Now;
writer.WriteLine("Time {0} Exception: {1}", time, e);
writer.Flush();
}
args.Handled = true;
MessageBox.Show(e.ToString());
}
private void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception)args.ExceptionObject;
using (StreamWriter writer = File.AppendText("ExceptionsLog.txt"))
{
DateTime time = DateTime.Now;
writer.WriteLine("Time {0} Exception: {1} Runtime termination: {2}", time, e.Message, args.IsTerminating);
writer.Flush();
}
MessageBox.Show(e.ToString());
}
private void CurrentOnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs args)
{
Exception e = (Exception)args.Exception;
using (StreamWriter writer = File.AppendText("ExceptionsLog.txt"))
{
DateTime time = DateTime.Now;
writer.WriteLine("Time {0} Exception: {1}", time, e);
writer.Flush();
}
args.Handled = true;
MessageBox.Show(e.ToString());
}
For handling unhandled exceptions, please create a method like this
protected TResult LogFailedOperations<TResult>(Func<TResult> action)
{
try
{
return action();
}
catch (Exception ex)
{
// Logic for logging from ex.Message
}
}
Also, when you perform any method, just enclose that method around this LogFailedOperations method like these examples -
private void MyButton_Click(object sender, RoutedEventArgs e)
{
var result = LogFailedOperations(() => { /* Your logic for button click */ });
}
private void LoadDataToView()
{
var result = LogFailedOperations(() => { /* Your logic for laoding data */ });
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
var result = LogFailedOperations(() => { /* Your logic for slider changed event */ });
}

Categories