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.
Related
I'm trying to use this pre-made C# tftp server app with my windows c# form. In the authors server example, which works great, he uses a console app. When I trying porting his console example into my form app it doesn't work (no errors, just doesn't connect) and I believe my issue is in the "using" statement:
using (var server = new TftpServer())
{
server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
server.Start();
Console.Read();
}
Not sure if I understand correctly but I believe the Console.Read() blocks keeping the app from exiting. If this is the case how would I implement a equivalent with a form app. I just can't get my head around the "using". Sorry I'm new to c#.
Windows Forms will always remain open until they're explicitly closed by the user. They always have a thread reading the message queue for user input, so they won't exit the same way an unrestrained console application will. In Windows Forms, we have to worry a bit more about multithreading and concurrency than we would in console apps. It mostly comes naturally, but not always.
Because of that, you can't really use an equivalent to Console.Read() to hold off execution of the using disposal until the user requests it. If you did, your form would simply appear unresponsive.
However, you're in luck! A using block in C# is nothing more than syntactic sugar for remembering to call IDisposable.Dispose() after you're done with an object. So the equivalent to this in a Forms project could just be storing the server object in a class-wide field, then calling server.Dispose() on, say, a Button.Click event. That's, of course, just an example. You could also do it on Form.Closing if that felt more appropriate.
High-level, you want to do something like this:
Declare a field in your form class TftpServer server;.
Register a Load event and whatever you need for your server to function in your constructor.
Open your server field in the Form_Load event.
Use the server's events as you see so fit during the life of your Form. You may or may not have to worry about concurrency, but that's a matter for another question.
Call server.Dispose() in the form's Dispose event.
In essence,
class main : Form
{
private TftpServer server;
public main()
{
InitializeComponent();
this.Load += main_Load;
server = new TftpServer();
server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
}
private void main_Load(object sender, EventArgs e)
{
server.Start();
}
private void server_OnReadRequest(/* I wasn't sure of the arguments here */)
{
// use the read request: give or fetch its data (depending on who defines "read")
}
private void server_OnWriteRequest(/* I wasn't sure of the arguments here */)
{
// use the write request: give or fetch its data (depending on who defines "write")
}
protected override void Dispose(bool disposing)
{
if (server != null) // since Dispose can be called multiple times
{
server.Dispose();
server = null;
}
}
}
The problem is that disposing the server is what is closing it. Keep in mind using is just syntactic sugar. The following two code chunks are [practically] equivalent:
var foo = new Foo();
try
{
foo.Do();
}
finally
{
foo.Dispose();
}
using (var foo = new Foo())
{
foo.Do();
}
You are fine blocking the main thread from exiting in a Console app, but in a Forms app it's different. The problem is not that you need to hold the thread inside the using by doing some sort of blocking operation. That would be bad, and the behavior would lock up your forms app. The problem is you don't want to use using. You want to new it up when you start the server, and then later on, on application exit, or on a stop click, explicitly dispose it with Dispose().
In a console application your TftpServer instance is listening until the thread exits which is only after a key is pressed which is detected by Console.Read()
In your forms app that Console.Read() isn't waiting around and so the using block finishes and that causes your server instance to fall out of scope.
So you are not exactly misusing the using but rather the intended use is not helping you at all. Take a look at using the task parallel library to let some background tasks run asynchronously.
A small note that also doubles as an answer, you could use a using block here, you just put it in your main function:
...(make your form and stuff)
using (var server = new TftpServer())
{
server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
server.Start();
Application.Run(yourFormHere); //This blocks until the form is closed
}
Another option I forgot to mention is overriding Dispose in your Form. You probably want to do this. With this option you're guaranteed your server will be disposed (bar some event that would prevent it from being disposed either way [ie. being out of memory])
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().
I'm looking into doing some Unity3D scripting stuff, and I'd like to set up global exception handling system. This is not for running in the release version of the game, the intention is to catch exceptions in user scripts and also in editor scripts and make sure they are forwarded to a database for analysis (and also to send email to relevant devs so they can fix their shizzle).
In a vanilla C# app I'd have a try-catch around the Main method. In WPF I'd hook one or more of the unhandled exception events. In Unity...?
So far the best I've been able to come up with is something like this:
using UnityEngine;
using System.Collections;
public abstract class BehaviourBase : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
try
{
performUpdate();
print("hello");
}
catch (System.Exception e)
{
print(e.ToString());
}
}
public abstract void performUpdate();
}
In other scripts, I derive BehaviourBase instead of MonoBehavior and implement performUpdate() instead of Update(). I haven't implemented a parallel version for Editor clases but I assume I'd have to do the same thing there.
I don't like this strategy, however, because I'll have to backport it to any scripts we grab from the community (and I'll have to enforce it on the team). The Editor scripts don't have a single point of entry comparable to MonoBehavior either, so I assume I'd have to implement exception safe versions of wizards, editors and so on.
I've seen suggestions about catching log messages (as opposed to exceptions) using Application.RegisterLogCallback, but this makes me uncomfortable because I'd need to parse the debug log string rather than having access to the actual exceptions and stacktraces.
So... what's the right thing to do?
Create an empty GameObject in your scene and attach this script to it:
using UnityEngine;
public class ExceptionManager : MonoBehaviour
{
void Awake()
{
Application.logMessageReceived += HandleException;
DontDestroyOnLoad(gameObject);
}
void HandleException(string logString, string stackTrace, LogType type)
{
if (type == LogType.Exception)
{
//handle here
}
}
}
make sure there is one instance.
The rest is up to you. You can also store the logs in file system, web server or cloud storage.
Note that DontDestroyOnLoad(gameObject) makes this GameObject persistent, by preventing it from being destroyed in case of scene change.
There is a working implementation of RegisterLogCallback that I found here: http://answers.unity3d.com/questions/47659/callback-for-unhandled-exceptions.html
In my own implementation I use it to call my own MessageBox.Show instead of writing to a log file. I just call SetupExceptionHandling from each of my scenes.
static bool isExceptionHandlingSetup;
public static void SetupExceptionHandling()
{
if (!isExceptionHandlingSetup)
{
isExceptionHandlingSetup = true;
Application.RegisterLogCallback(HandleException);
}
}
static void HandleException(string condition, string stackTrace, LogType type)
{
if (type == LogType.Exception)
{
MessageBox.Show(condition + "\n" + stackTrace);
}
}
I also now have the error handler email me via this routine, so I always know when my app crashes and get as much detail as possible.
internal static void ReportCrash(string message, string stack)
{
//Debug.Log("Report Crash");
var errorMessage = new StringBuilder();
errorMessage.AppendLine("FreeCell Quest " + Application.platform);
errorMessage.AppendLine();
errorMessage.AppendLine(message);
errorMessage.AppendLine(stack);
//if (exception.InnerException != null) {
// errorMessage.Append("\n\n ***INNER EXCEPTION*** \n");
// errorMessage.Append(exception.InnerException.ToString());
//}
errorMessage.AppendFormat
(
"{0} {1} {2} {3}\n{4}, {5}, {6}, {7}x {8}\n{9}x{10} {11}dpi FullScreen {12}, {13}, {14} vmem: {15} Fill: {16} Max Texture: {17}\n\nScene {18}, Unity Version {19}, Ads Disabled {18}",
SystemInfo.deviceModel,
SystemInfo.deviceName,
SystemInfo.deviceType,
SystemInfo.deviceUniqueIdentifier,
SystemInfo.operatingSystem,
Localization.language,
SystemInfo.systemMemorySize,
SystemInfo.processorCount,
SystemInfo.processorType,
Screen.currentResolution.width,
Screen.currentResolution.height,
Screen.dpi,
Screen.fullScreen,
SystemInfo.graphicsDeviceName,
SystemInfo.graphicsDeviceVendor,
SystemInfo.graphicsMemorySize,
SystemInfo.graphicsPixelFillrate,
SystemInfo.maxTextureSize,
Application.loadedLevelName,
Application.unityVersion,
GameSettings.AdsDisabled
);
//if (Main.Player != null) {
// errorMessage.Append("\n\n ***PLAYER*** \n");
// errorMessage.Append(XamlServices.Save(Main.Player));
//}
try {
using (var client = new WebClient()) {
var arguments = new NameValueCollection();
//if (loginResult != null)
// arguments.Add("SessionId", loginResult.SessionId.ToString());
arguments.Add("report", errorMessage.ToString());
var result = Encoding.ASCII.GetString(client.UploadValues(serviceAddress + "/ReportCrash", arguments));
//Debug.Log(result);
}
} catch (WebException e) {
Debug.Log("Report Crash: " + e.ToString());
}
}
Unity devs just do not provide us with tools like that. They catch exceptions internally in framework here and there and log them as strings, giving us Application.logMessageReceived[Threaded]. So, if you need exceptions to happen or be logged with your own processing (not unity's) I can think of:
do not use framework mechanics, but use your own so exception is not caught by framework
make your own class implementing UnityEngine.ILogHandler:
public interface ILogHandler
{
void LogFormat(LogType logType, Object context, string format, params object[] args);
void LogException(Exception exception, Object context);
}
And use it as said in official docs to log your exceptions. But that way you do not receive unhandled exceptions and exceptions logged from plugins (yes, someone do log exceptions in frameworks instead of throwing them)
Or you can make a suggestion/request to unity to make Debug.unityLogger (Debug.logger is deprecated in Unity 2017) have setter or other mechanism so we can pass our own.
Just set it with reflection. But it's temporary hack and will not work when unity change code.
var field = typeof(UnityEngine.Debug)
.GetField("s_Logger", BindingFlags.Static | BindingFlags.NonPublic);
field.SetValue(null, your_debug_logger);
Note: To get correct stacktraces you need to set StackTraceLogType in editor settings/code to ScriptOnly (most times it's what you need, I wrote an article on how it work) And, when building for iOS, it is said that Script call optimization must be set to slow and safe
If interested, you can read how popular crash analytics tool works. If you look into crashlytics (crash report tool for android/ios), than you'll find out that it internally uses Application.logMessageReceived and AppDomain.CurrentDomain.UnhandledException events to log managed C# exceptions.
If interested in examples on unity framework catching exceptions, you may look at ExecuteEvents.Update And another article from me with testing it catching exception in button click listener can be found here.
Some summary on official ways to log unhandled exception:
I. Application.logMessageReceived is fired when exception happens on main thread. There are ways for it to happen:
exception caught in c# code and logged through Debug.LogException
exception caught in native code (probably c++ code when using il2cpp). In that case native code calls Application.CallLogCallback which results in firing Application.logMessageReceived
Note: StackTrace string will contain "rethrow" when original exception have inner exceptions
II. Application.logMessageReceivedThreaded is fired when exception happens on any thread, including main (it's said in docs) Note: it must be thread-safe
III. AppDomain.CurrentDomain.UnhandledException for example is fired when:
You call the following code in editor:
new Thread(() =>
{
Thread.Sleep(10000);
object o = null;
o.ToString();
}).Start();
But it causes crash on android 4.4.2 release build when using Unity 5.5.1f1
Note: I reproduced some bugs with unity missing stackframes when logging exceptions and assertions. I submited one of them.
You mentioned Application.RegisterLogCallback, have you tried implementing it? Because the logging callback passes back a stack trace, an error, and an error type (warning, error, etc).
The strategy you outline above would be tough to implement because MonoBehaviours don't just have a single entry point. You'd have to handle OnTriggerEvent, OnCollisionEvent, OnGUI, and so on. Each one wrapping its logic in an exception handler.
IMHO, exception handling is a bad idea here. If you don't immediately re-throw the exception, you'll end up propagating those errors in weird ways. Maybe Foo relies on Bar, and Bar on Baz. Say Baz throws an exception that is caught and logged. Then Bar throws an exception because the value it needs from Baz is incorrect. Finally Foo throws an exception because the value it was getting from Bar is invalid.
You can use a plugin called Reporter to receive an email of Debug Logs, Stack trace and screen capture on the moment of unhandled Error. Screen capture and stack trace are usually enough to figure out the reason of the Error. For stubborn sneaky Errors you should log more of suspicious data, build and wait again for the error.I Hope this helps.
I am trying to keep the (beta version of my) application running as much as possible,So I placed another try-catch inside Program.cs as well in cases where some critical errors occur and shut the application down unexpectedly.And in the catch i rewrote the Application.Run() method so that the application can resume itself after being terminated for what ever reason.
Is it right to have such a plan for this specific scenario?
If it is not right,Then what else is recommended in order to keep the program running?
This is the sample code demonstrating what i mean:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Hossein;
using Pishro.Classes;
namespace Pishro
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMain());
}
catch(Exception exc)
{
API.SaveAndShowLog(exc);
Application.Run(new frmMain());
}
}
}
}
Globally handling exceptions is a good idea for logging and alerting.
An automatic restart policy like yours can be useful, yes. There is a risk however: If the crash has corrupted global data-structures restarting the app can have unpredictable results like silent data corruption. For example, files might still be open and locked. Locks might not have been released. Static variables might be in an undefined state. Rogue threads might still be running, unaware that the application UI was destroyed.
I recommend that you restart the app by starting a new process of your application. Let the old process die.
I think your question involves a deeper question.. Should I catch all the exceptions?
To keep going you could catch them all.. but all those possible exceptions that you don't expect or not know are probably bugs.
Maybe you should try to implement better error handling approach within your app. So all the exceptions are known or expected.
Instead of wrapping a try catch around your application run method, consider handling the exceptions with events.
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
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("Exception handled");
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
}
Mainly the thread exception is the one you want but ideally - you would want to set up some form of logging/flagging the error to the user and still dispose of the program because it may cause the program to continue in an unfit state. Please put a button on your form and in the click event throw new Exception(""); and then the message box should display.
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.