We have a WPF application where parts of it may throw exceptions at runtime. I'd like to globally catch any unhandled exceptions and log them, but otherwise continue program execution as if nothing happened (kinda like VB's On Error Resume Next).
Is this possible in C#? And if so, where exactly would I need to put the exception handling code?
Currently I can't see any single point where I could wrap a try/catch around and which would catch all exceptions that could occur. Even then, I would have left whatever has been executed because of the catch. Or am I thinking in horribly wrong directions here?
ETA: Because many people below pointed it out: The application is not for controlling nuclear power plants. If it crashes, it's not that big a deal, but it throws random exceptions that are mostly UI-related that are a nuisance in the context where it would be used. There were (and probably still are) a few of those and since it uses a plugin architecture and may be extended by others (also students in that case; so no experienced developers that are able to write completely error-free code).
As for the exceptions that get caught: I do log them to a log file, including the complete stack trace. That was the whole point of that exercise. Just to counter those people that were taking my analogy to VB's OERN too literally.
I know that blindly ignoring certain classes of errors is dangerous and might corrupt my application instance. As said before, this program isn't mission-critical for anyone. No-one in their right mind would bet the survival of the human civilization on it. It's simply a little tool for testing certain design approaches wrt. software engineering.
For the immediate use of the application there are not many things that can happen on an exception:
No exception handling – error dialog and application exit. Experiment has to be repeated, though likely with another subject. No errors have been logged, which is unfortunate.
Generic exception handling – benign error trapped, no harm done. This should be the common case judged from all errors we were seeing during development. Ignoring this kind of errors should have no immediate consequences; the core data structures are tested well enough that they will easily survive this.
Generic exception handling – serious error trapped, possibly crash at a later point. This may happen rarely. We've never seen it so far. The error is logged anyway and a crash might be inevitable. So this is conceptually similar to the very first case, except that we have a stack trace. And in the majority of cases the user won't even notice.
As for the experiment data generated by the program: A serious error would at worst just cause no data to be recorded. Subtle changes that change the result of the experiment ever so slightly are pretty unlikely. And even in that case, if the results seem dubious the error was logged; one can still throw away that data point if it's a total outlier.
To summarize: Yes, I consider myself still at least partially sane and I don't consider a global exception handling routine which leaves the program running to be necessarily totally evil. As said twice before, such a decision might be valid, depending on the application. In this case it was judged a valid decision and not total and utter bullshit. For any other application that decision might look different. But please don't accuse me or the other people who worked on that project to potentially blow up the world just because we're ignoring errors.
Side note: There is exactly one user for that application. It's not something like Windows or Office that gets used by millions where the cost of having exceptions bubble to the user at all would be very different in the first place already.
Use the Application.DispatcherUnhandledException Event. See this question for a summary (see Drew Noakes' answer).
Be aware that there'll be still exceptions which preclude a successful resuming of your application, like after a stack overflow, exhausted memory, or lost network connectivity while you're trying to save to the database.
Example code using NLog that will catch exceptions thrown from all threads in the AppDomain, from the UI dispatcher thread and from the async functions:
App.xaml.cs :
public partial class App : Application
{
private static Logger _logger = LogManager.GetCurrentClassLogger();
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
SetupExceptionHandling();
}
private void SetupExceptionHandling()
{
AppDomain.CurrentDomain.UnhandledException += (s, e) =>
LogUnhandledException((Exception)e.ExceptionObject, "AppDomain.CurrentDomain.UnhandledException");
DispatcherUnhandledException += (s, e) =>
{
LogUnhandledException(e.Exception, "Application.Current.DispatcherUnhandledException");
e.Handled = true;
};
TaskScheduler.UnobservedTaskException += (s, e) =>
{
LogUnhandledException(e.Exception, "TaskScheduler.UnobservedTaskException");
e.SetObserved();
};
}
private void LogUnhandledException(Exception exception, string source)
{
string message = $"Unhandled exception ({source})";
try
{
System.Reflection.AssemblyName assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName();
message = string.Format("Unhandled exception in {0} v{1}", assemblyName.Name, assemblyName.Version);
}
catch (Exception ex)
{
_logger.Error(ex, "Exception in LogUnhandledException");
}
finally
{
_logger.Error(exception, message);
}
}
AppDomain.UnhandledException Event
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.
public App()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
}
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);
}
If the UnhandledException event is handled in the default application
domain, it is raised there for any unhandled exception in any thread,
no matter what application domain the thread started in. If the thread
started in an application domain that has an event handler for
UnhandledException, the event is raised in that application domain. If
that application domain is not the default application domain, and
there is also an event handler in the default application domain, the
event is raised in both application domains.
For example, suppose a thread starts in application domain "AD1",
calls a method in application domain "AD2", and from there calls a
method in application domain "AD3", where it throws an exception. The
first application domain in which the UnhandledException event can be
raised is "AD1". If that application domain is not the default
application domain, the event can also be raised in the default
application domain.
In addition what others mentioned here, note that combining the Application.DispatcherUnhandledException (and its similars) with
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="1" />
</runtime>
</configuration>
in the app.config will prevent your secondary threads exception from shutting down the application.
Here is complete example using NLog
using NLog;
using System;
using System.Windows;
namespace MyApp
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private static Logger logger = LogManager.GetCurrentClassLogger();
public App()
{
var currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = (Exception)e.ExceptionObject;
logger.Error("UnhandledException caught : " + ex.Message);
logger.Error("UnhandledException StackTrace : " + ex.StackTrace);
logger.Fatal("Runtime terminating: {0}", e.IsTerminating);
}
}
}
in Wpf application Project follow this Steps:
in App.xaml.cs file:
using 'System.Windows.Threading'
create App_DispatcherUnhandledException method same example.
example:
using System.Windows;
using System.Windows.Threading;
namespace Test
{
public partial class App : Application
{
void App_DispatcherUnhandledException(object sender,
DispatcherUnhandledExceptionEventArgs e)
{
// Process unhandled exception
// Prevent default unhandled exception processing
e.Handled = true;
}
}
}
in App.xaml:
add DispatcherUnhandledException="App_DispatcherUnhandledException"
for Example:
<Application x:Class="eValGr.UI.Light.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:eValGr.UI.Light"
DispatcherUnhandledException="Application_DispatcherUnhandledException">
<Application.Resources>
</Application.Resources>
</Application>
Like "VB's On Error Resume Next?" That sounds kind of scary. First recommendation is don't do it. Second recommendation is don't do it and don't think about it. You need to isolate your faults better. As to how to approach this problem, it depends on how you're code is structured. If you are using a pattern like MVC or the like then this shouldn't be too difficult and would definitely not require a global exception swallower. Secondly, look for a good logging library like log4net or use tracing. We'd need to know more details like what kinds of exceptions you're talking about and what parts of your application may result in exceptions being thrown.
Related
I'm using a crappy third party library because unfortunately I have no choice. This library creates a bunch of threads internally when I call it, and occasionally throws a NullReferenceException on one of these threads. Is there any way for me to catch these exceptions even though I don't own the thread that throws them? I have no way to change the third party code.
As a simple example to show the problem:
public static void main()
{
try
{
var crappyLib = new CrappyLibrary();
crappyLib.DoCrappyThings();
}
catch
{
Console.WriteLine("This never happens");
}
}
// I do not own the following code, I can't change it
public class CrappyLibrary
{
public void DoCrappyThings()
{
var t = new Thread(DoWork);
t.Start();
}
private void DoWork()
{
throw new ThisLibrarySucksException();
}
}
The thing worrying me most in the described case is abnormal thread termination inside that 3rd-party lib. Once a thread is throwing, you can't catch the exception via correct way because you're not the owner of that thread invocation (and it has no idea it should propagate the exception to you; unlike it happens in TPL, let say). So even if handling such exceptions via a global handler this could be incorrect way because the lib can appear in non-consistent state after any of such exceptions.
So the safe way here is to isolate the lib inside some scope and re-launch the scope after any exception. Let say, to load the lib into separate domain.
If your goal is to prevent early termination of your process because of these unhandled exceptions that are not under your control, then there exists the legacyUnhandledExceptionPolicy setting that you can add to your app.config that will prevent unhandled thread exceptions from terminating the whole process.
Obviously, the solution is not perfect, as unhandled exceptions can destabilize the state of the threads. But at least it's an option you can consider.
Please have a look at the documentation about this here to better understand the implications of turning on this setting.
Your app.config would have to look something like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="1"/>
</runtime>
</configuration>
EDIT:
Just a thought, but perhaps the above setting, in combination with adding an event handler for AppDomain.UnhandledException can help you with your need.
Using AppDomain.UnhandledException, you can detect the failure, so that you know when you need to trigger a retry, or whatever else it is that you need to do in these cases.
And the legacyUnhandledExceptionPolicy setting would still be useful to prevent the process from shuting down, thus giving you the opportunity to perform the retry.
I hope this is helpful https://msdn.microsoft.com/en-GB/library/system.windows.forms.application.threadexception.aspx
You can try something like that (it's from the article)
Application.ThreadException += new ThreadExceptionEventHandler (ErrorHandlerForm.Form1_UIThreadException);
// 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 non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
I have been crawling the Internet for quite a long time in hope of a solution, and I've come across a number of answers, but none of these seem to achieve what I want.
I'm trying to handle exceptions without causing the app to crash. Rather than the app simply exiting, I would rather capture the exception, present the user with a more user-friendly error (perhaps a messagebox warning) and allow them to continue operation in the app.
Is it possible to stop the app from bailing out?
The way I'm currently attempting to catch this is like the following:
public class Login : Activity
{
int count = 1;
Session mySession;
protected override void OnCreate(Bundle bundle)
{
AndroidEnvironment.UnhandledExceptionRaiser += HandleAndroidException;
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Login);
Button button = FindViewById<Button>(Resource.Id.Login);
string accountCode = Resource.Id.AccountCode.ToString();
string password = Resource.Id.Password.ToString();
// button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };
button.Click += delegate
{
throw new Exception("LETS THROW A RANDOM EXCEPTION");
};
}
void HandleAndroidException(object sender, RaiseThrowableEventArgs e)
{
Log.Error("INTERNAL DEBUG", "PLEASE HANDLE MY EXCEPTION!");
e.Handled = true;
System.Console.Write("YOU'VE JUST BEEN HANDLED!");
}
}
As you can see I am throwing a general exception and attempting to catch this with an UnhandledExceptionRaiser. I used this as a reference: http://androidapi.xamarin.com/index.aspx?link=E%3AAndroid.Runtime.AndroidEnvironment.UnhandledExceptionRaiser
I am able to find my message in the "Android Device Logging" tool, however it is being triggered AFTER an unhandled exception error occurs. I think this means something inside of Xamarin is having first crack at the exception and falling over. Surely there has to be a way of stopping this??
I have seen countless examples online where people have been asking similar questions and there has been no clear solution. Some people have offered some solutions, but these don't actually do what I had anticipated.
It is literally mind boggling to me if this cannot be done.
This is my first time using Xamarin and also my first time developing a mobile app so I apologise if I'm being ignorant about anything.
Please help!!!
There is one important thing you have to understand about the nature of an Unhandled exception in Android, there isn't one.... in Android framework which uses Java it's an Uncaught exception which means you can't "handle" it or recover from it like you maybe would in a .Net environment. Xamarin(Mono) internally "handles" those uncaught exceptions by surrounding literally everything with try-catch and raising the Unhandled event but that is besides the point. It is also discouraged to interact with the UI as well for various reasons.
Theoretically there are several "workarounds" for displaying a dialog to the user or restarting the app, none of which I'd recommend on doing. Instead you should surround sensitive areas with try-catch clauses to handle expected exceptions, as for the unexpected one's just use an exception reporting component and update your app after analyzing the reported exceptions.
Also, I would move the event subscription to the Application class but that is a personal preference.
Like so:
public class YourAppClass : Application
{
public override void OnCreate()
{
AndroidEnvironment.UnhandledExceptionRaiser += HandleAndroidException;
}
}
I was thinking, is it possible to "override" or maybe replace the standard winforms .net Exception form??
I am talking about this dude:
Is it possible, during the scope of the hole program, to override this windows? I mean automatically, without having to perform try/catch.
You can handle System.Windows.Forms.Application.ThreadException event to show your custom message.
You should handle both the following events:
AppDomain.CurrentDomain.UnhandledException
Application.ThreadException
In those handlers you could display a custom form that you made.
This is the ThreadExceptionDialog class, it derives from the Form class. Deriving from it to alter the dialog is a lost cause, you can't easily get to the embedded controls. You can create your own Form derived class to make your own dialog just as well, just give it a constructor that takes an Exception argument. Implement an event handler for Application.ThreadException to display it.
Do note the fundamental flaw in the dialog. It expects the user to make the right choice when she needs to click a button to dismiss the dialog. With, in general, fairly obscure information about what exactly went wrong. It means something to you, rarely anything more than 'oh crap' to the user. Clicking the Continue button is not typically the right thing to do.
To avoid the user having to make such a difficult choice, call Application.SetUnhandledExceptionMode() in your Main() method, passing ThrowException so that the event is never raised. Every unhandled exception now goes through AppDomain.UnhandledException. Including the ones that were raised in a worker thread, exceptions that don't produce the dialog. Write an event handler for it and display and/or log the value of e.ExceptionObject.ToString(). It is up to you to sort out a way to get that info to your desk, or the user's IT staff, so you can improve your product and they can get their machines stable.
In webforms, you can handle Application_Error in global.asax. But it seems like you're talking about winforms. In that case:
try adding the following code into your main starter method:
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(ExceptionHandler.OnThreadException);
And define the ExceptionHandler class as follows:
/// <summary>
/// Main thread error handler.
/// </summary>
public sealed class ExceptionHandler
{
private ExceptionHandler()
{}
/// <summary>
/// Handles an exception on the main thread.
/// </summary>
/// <param name="sender"></param>
/// <param name="t"></param>
public static void OnThreadException(object sender, ThreadExceptionEventArgs t)
{
DialogResult result = DialogResult.Cancel;
try
{
result = ShowThreadExceptionDialog(t.Exception);
}
catch
{
try
{
MessageBox.Show("Fatal Error", "Application Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
finally
{
Application.Exit();
}
}
// Exits the program when the user clicks Abort.
if (result == DialogResult.Abort)
Application.Exit();
}
// Creates the error message and displays it.
private static DialogResult ShowThreadExceptionDialog(Exception e)
{
string errorMsg = "An error occurred please contact the adminstrator with the following information:\n\n";
errorMsg = errorMsg + e.Message + "\n\nStack Trace:\n" + e.StackTrace;
return MessageBox.Show(errorMsg, "Application Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop);
}
}
taken from: http://www.eggheadcafe.com/community/aspnet/2/27469/any-method-for-handling-error-globally-in-c.aspx
Check this link.
From the page:
Introduction
One of the things that impressed me when I first started learning .NET was its enhanced exception-handling functionality. By this I mean such features as easy access to the type of exception thrown, full stack trace and inner exceptions. This makes it easy to still get full information in those places where you just catch a top-level System.Exception. I find this convenient since, if you don't need to take specific action on a particular type of exception, it is tedious to have successive catch handlers for each type of exception that may be thrown. In any case, even if you do catch specific exceptions you usually also need to catch System.Exception just to cover yourself and prevent program crashes. Thus I find that I end up catching System.Exception all over the place in my code. A typical scenario is that in Windows Forms and ASP.NET Web Forms applications, all of my non-trivial event handlers end up containing try-catch System.Exception blocks.
The trouble is that this does still clutter up the code somewhat and doesn't really seem quite right. Is there a better way?
This is a follow up to my initial question and I would like to present my findings and ask for corrections, ideas and insights. My findings (or rather interpretations) come from people's answers to my previous question, reading MSDN .NET 3.5 documentation and debugging .NET 3.5 code. I hope this will be of value to someone who was wondering like me how to detect when an application terminates.
Events:
System.AppDomain.CurrentDomain.ProcessExit: raised when process exits, e.g. after the default AppDomain and everything else was unloaded [Total execution time is limited to just 3 seconds!]. For WPF, use System.Windows.Application.Exit instead. For Windows Forms, run code after Application.Run(...) in main method.
System.AppDomain.CurrentDomain.DomainUnload: raised when an AppDomain other than default AppDomain unloads, e.g. when running classes with unit testing frameworks (MbUnit with TestDriven.NET).
System.AppDomain.CurrentDomain.UnhandledException: (if handled in default AppDomain:) raised for any unhandled exception in any thread, no matter what AppDomain the thread started in. This means, this can be used as the catch-all for all unhandled exceptions.
System.Windows.Application.Exit: raised when WPF application (i.e. the default AppDomain) exits gracefully. Override System.Windows.Application.OnExit to take advantage of it.
Finalizers (destructors in C#): run when garbage collector frees unmanaged resources. [Total execution time is limited!].
Order of events:
WPF application: graceful exit
System.Windows.Application.Exit
System.AppDomain.CurrentDomain.ProcessExit
Finalizers
WPF application: unhandled exception
System.AppDomain.CurrentDomain.UnhandledException
MbUnit running inside TestDriven.NET: passed test (graceful exit)
System.AppDomain.CurrentDomain.DomainUnload
Finalizers
MbUnit running inside TestDriven.NET: failed test (unhandled exceptions are handled by MbUnit)
AppDomain.CurrentDomain.DomainUnload
Finalizers
Questions:
Are my interpretations/findings correct?
Do you know of more details that I have
left out? E.g. what is the total
execution time for finalizers?
Do you know of any other events /
ideas that I be aware of?
What events are there and what order do they get raised in other applications, e.g. Windows Forms, Web Service, ASP.NET web site, etc?
Prompted by ssg31415926's question/answer (this question is a bit reversed), there's also Application.SessionEnding which is called when the when the user logs off or shuts down. It is called before the Exit event.
When Dispatcher.BeginInvokeShutdown() is called, Application.Exit will not be called.
The default timeout for a finalizer's execution is 2 seconds.
You write:
System.AppDomain.CurrentDomain.UnhandledException: (if handled in default AppDomain:) raised for any unhandled exception in any thread, no matter what AppDomain the thread started in. This means, this can be used as the catch-all for all unhandled exceptions.
I do not think that this is correct. Try the following code:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AppDomainTestingUnhandledException
{
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException +=
(sender, eventArgs) => Console.WriteLine("Something went wrong! " + args);
var ad = AppDomain.CreateDomain("Test");
var service =
(RunInAnotherDomain)
ad.CreateInstanceAndUnwrap(
typeof(RunInAnotherDomain).Assembly.FullName, typeof(RunInAnotherDomain).FullName);
try
{
service.Start();
}
catch (Exception e)
{
Console.WriteLine("Crash: " + e.Message);
}
finally
{
AppDomain.Unload(ad);
}
}
}
class RunInAnotherDomain : MarshalByRefObject
{
public void Start()
{
Task.Run(
() =>
{
Thread.Sleep(1000);
Console.WriteLine("Uh oh!");
throw new Exception("Oh no!");
});
while (true)
{
Console.WriteLine("Still running!");
Thread.Sleep(300);
}
}
}
}
As far as I can tell, the UnhandledException handler is never called, and the thread will just silently crash (or nag at you if you run it in the debugger).
Just add a new event on your main form:
private void frmMain_Load(object sender, EventArgs e)
{
Application.ApplicationExit += new EventHandler(this.WhenItStopsDoThis);
}
private void WhenItStopsDoThis(object sender, EventArgs e)
{
//Program ended. Do something here.
}
I'm wondering what the best way is to have a "if all else fails catch it".
I mean, you're handling as much exceptions as possible in your application,
but still there are bound to be bugs, so I need to have something that
catches all unhandled exceptions so I can collect information and store
them in a database or submit them to a web service.
Does the AppDomain.CurrentDomain.UnhandledException event capture everything?
Even if the application is multithreaded?
Side note: Windows Vista exposes native API functions that allow any application
to recover itself after a crash... can't think of the name now... but I'd rather not
use it, as many of our users are still using Windows XP.
I have just played with AppDomain's UnhandledException behavior,
(this is the last stage the unhandled exception is registered at)
Yes, after processing the event handlers your application will be terminated and the nasty "... program stopped working dialog" shown.
:)
You still can avoid that.
Check out:
class Program
{
void Run()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Console.WriteLine("Press enter to exit.");
do
{
(new Thread(delegate()
{
throw new ArgumentException("ha-ha");
})).Start();
} while (Console.ReadLine().Trim().ToLowerInvariant() == "x");
Console.WriteLine("last good-bye");
}
int r = 0;
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Interlocked.Increment(ref r);
Console.WriteLine("handled. {0}", r);
Console.WriteLine("Terminating " + e.IsTerminating.ToString());
Thread.CurrentThread.IsBackground = true;
Thread.CurrentThread.Name = "Dead thread";
while (true)
Thread.Sleep(TimeSpan.FromHours(1));
//Process.GetCurrentProcess().Kill();
}
static void Main(string[] args)
{
Console.WriteLine("...");
(new Program()).Run();
}
}
P.S. Do handle the unhandled for Application.ThreadException (WinForms) or DispatcherUnhandledException (WPF) at the higher level.
In ASP.NET, you use the Application_Error function in the Global.asax file.
In WinForms, you use the MyApplication_UnhandledException in the ApplicationEvents file
Both of these functions are called if an unhandled exception occurs in your code. You can log the exception and present a nice message to the user from these functions.
For Winform applications, in addition to AppDomain.CurrentDomain.UnhandledException I also use Application.ThreadException and Application.SetUnhandledExceptionMode (w/ UnhandledExceptionMode.CatchException). This combination seems to catch everything.
On the main thread, you have the following options:
Console or Service application: AppDomain.CurrentDomain.UnhandledException
WinForms application: Application.ThreadException
Web application: Global.asax's Application_Error
For other threads:
Secondary threads have no unhandled-exceptions; use SafeThread
Worker threads: (timer, threadpool) there is no safety net at all!
Bear in mind that these events do not handle exceptions, they merely report them to the application--often when it is far too late to do anything useful/sane about them
Logging exceptions is good, but monitoring applications is better ;-)
Caveat: I am the author of the SafeThread article.
For WinForms, don't forget to attach to the current Thread's unhandled exception event too (especially if you are using multi threading).
Some links on best practices here and here and here (probably the best exception handling article for .net)
There's also a cool thing called ELMAH that will log any ASP.NET errors that occur in a web application. I know you're asking about a Winform App solution, but I felt this could be beneficial to anyone needing this type of thing on a web app. We use it where I work and it's been very helpful in debugging (especially on production servers!)
Here's some features that it has (pulled right off the page):
Logging of nearly all unhandled exceptions.
A web page to remotely view the entire log of recoded exceptions.
A web page to remotely view the full details of any one logged exception.
In many cases, you can review the original yellow screen of death that
ASP.NET generated for a given
exception, even with customErrors mode
turned off.
An e-mail notification of each error at the time it occurs.
An RSS feed of the last 15 errors from the log.
A number of backing storage implementations for the log, including
in-memory, Microsoft SQL Server and
several contributed by the community.
You can monitor most exceptions in that handler even in multithreaded apps, but .NET (starting with 2.0) won't allow you to cancel unhandled exceptions unless you enable the 1.1 compatibility mode. When that happens the AppDomain will be shut down no matter what. The best you could do is launch the app in a different AppDomain so that you can handle this exception and create a new AppDomain to restart the app.
I am using the following approach, which works and reduces greatly the amount of code ( yet I am not sure if there is a better way or what the pitfalls of it might be.
Whenever you call:
I quess the quys giving minuses would be polite enough to clarify their actions ; )
try
{
CallTheCodeThatMightThrowException()
}
catch (Exception ex)
{
System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace ();
Utils.ErrorHandler.Trap ( ref objUser, st, ex );
} //eof catch
And here is the ErrorHandler code :
Just to make clear- : objUser - is the object modelling the appusers ( you might get info such as domain name , department , region etc. for logging purposes
ILog logger - is the logging object - e.g. the one performing the logging activities
StackTrace st - the StackTrace object giving you debugging info for your app
using System;
using log4net; //or another logging platform
namespace GenApp.Utils
{
public class ErrorHandler
{
public static void Trap ( Bo.User objUser, ILog logger, System.Diagnostics.StackTrace st, Exception ex )
{
if (ex is NullReferenceException)
{
//do stuff for this ex type
} //eof if
if (ex is System.InvalidOperationException)
{
//do stuff for this ex type
} //eof if
if (ex is System.IndexOutOfRangeException)
{
//do stuff for this ex type
} //eof if
if (ex is System.Data.SqlClient.SqlException)
{
//do stuff for this ex type
} //eof if
if (ex is System.FormatException)
{
//do stuff for this ex type
} //eof if
if (ex is Exception)
{
//do stuff for this ex type
} //eof catch
} //eof method
}//eof class
} //eof namesp
In a manged GUI app, by default, exceptions that originate in the GUI thread are handled by whatever is assigned to the Application.ThreadException.
Exceptions that originate in the other threads are handled by AppDomain.CurrentDomain.UnhandledException.
If you want your GUI thread exceptions to work just like your-non GUI ones, so that they get handled by AppDomain.CurrentDomain.UnhandledException, you can do this:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
An advantage to catching the GUI thread exceptions using ThreadException is that you can give the use the options of letting the app continue. To make sure no config files are overriding default behavior, you can call:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
You are still vulnerable to exceptions from badly behaved native dlls. If a native dll installs its own handler using Win32 SetUnhandledExceptionFilter, it is supposed to save the pointer to the previous filter and call it too. If it doesn't do that, your handler wont' get called.