I noticed a few strange behaviors in a Windows Forms scenario which involves threads and UI, so, naturally, this means making use of the InvokeRequired property. The situation: my application makes use of a thread to do some work and the thread sends an event into the UI. The UI displays a message based on an Internationalization system which consists of a dictionary with keys. The I18N system cannot find a key in the dictionary and crashes.
Notes: application is in Debug Mode and I have a try-catch over the entire "Application.Run();" back in Program.cs. However, that try-catch is not reached, as what I will discuss here is based on inner Exception handling, but I mentioned it just in case.
So now here comes the fun parts:
Why, for the life of me, does Visual Studio "censor" exception information from me? In the code below, you will see on the if (InvokeRequired) branch, a try-catch. I log the exception. ex.InnerException is NULL and the provided ex.StackTrace is anemic (only 1 step in it). Now if I comment the try-catch and simply let it crash via the Debugger, I get a much ampler stack trace. Why is that?
To make things worse, neither of the two stack traces versions contain any information about the i18N crash. They just say "The given key was not present in the dictionary." and give me a stack trace up to the Invoke declaration.
On the else branch (that is, InvokeRequired == false), if I put a try-catch, I can successfully catch my Exception back to the i18n system. As you can see, I tried to send my exception with InnerException back to the InvokeRequired == true branch. However, even so, InnerException stays NULL there and I cannot access my i18N error.
I am puzzled by all these things and maybe somebody can help shed some light over here. If you got really strong lanterns that is.
Here is the function's code.
private delegate void AddMessageToConsole_DELEGATE (frmMainPresenter.PresenterMessages message);
private void AddMessageToConsole (frmMainPresenter.PresenterMessages message)
{
if (InvokeRequired)
{ //Catching any errors that occur inside the invoked function.
try { Invoke(new AddMessageToConsole_DELEGATE(AddMessageToConsole), message); }
catch (Exception ex) { MSASession.ErrorLogger.Log(ex); }
//Invoke(new AddMessageToConsole_DELEGATE(AddMessageToConsole), message);
}
else
{
string message_text = ""; //Message that will be displayed in the Console / written in the Log.
try
{
message_text = I18N.GetTranslatedText(message)
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
txtConsole.AppendText(message_text);
}
}
Yes, this is built-in behavior for Control.Invoke(). It only marshals the deepest nested InnerException back to the caller. Not so sure why they did this, beyond avoiding reporting exceptions that were raised by the marshaling code and would confuzzle the reader. It was done explicitly, you cannot change the way it works.
But keep your eyes on the ball, the real problem is that the string indeed cannot be found in the dictionary. The reason for that is that your background thread runs with a different culture from your UI thread. Different cultures have different string comparison rules. You either need to give your dictionary a different comparator (StringComparer.InvariantCulture) or you should switch your background thread to the same culture as your UI thread.
Dealing with a non-system default culture in your UI thread can be difficult, all other threads will be started with the system default. Especially threadpool threads are troublesome, you don't always control how they get started. And culture is not part of the Thread.ExecutionContext so doesn't get forwarded. This can cause subtle bugs, like the one you ran into. Other nastiness is, say, SortedList which suddenly becomes unsorted when read by a thread that uses a different culture. Using the system default culture is strongly recommended. Its what your user is likely to use anyway.
The call stack problem is a known issue with Control.Invoke. You lose the call stack. Sorry. This is because it is rethrown on the UI thread using throw ex;.
The best solution would be to replace the background thread with a background Task. Note: this solution is only available for .NET 4.0. The Task class properly marshals exceptions. I wrote a blog entry about reporting progress from tasks, and the code in that blog entry will allow you to catch any UI update errors in the background thread, preserving the original exception and its call stack.
If you can't upgrade to .NET 4.0 yet, there is a workaround. Microsoft's Rx library includes a CoreEx.dll which has an extension method for Exception called PrepareForRethrow. This is supported in .NET 3.5 SP1 and .NET 4.0 (and SL 3 and SL 4). You'll need to wrap your UI updater method with something a little uglier:
private delegate void AddMessageToConsole_DELEGATE (frmMainPresenter.PresenterMessages message);
private void AddMessageToConsole (frmMainPresenter.PresenterMessages message)
{
if (InvokeRequired)
{
// Invoke the target method, capturing the exception.
Exception ex = null;
Invoke((MethodInvoker)() =>
{
try
{
AddMessageToConsole(message);
}
catch (Exception error)
{
ex = error;
}
});
// Handle error if it was thrown
if (ex != null)
{
MSASession.ErrorLogger.Log(ex);
// Rethrow, preserving exception stack
throw ex.PrepareForRethrow();
}
}
else
{
string message_text = ""; //Message that will be displayed in the Console / written in the Log.
try
{
message_text = I18N.GetTranslatedText(message)
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
txtConsole.AppendText(message_text);
}
}
Note: I recommend you start a migration away from ISynchronizeInvoke. It is an outdated interface that is not carried forward into newer UI frameworks (e.g., WPF, Silverlight). The replacement is SynchronizationContext, which supports WinForms, WPF, Silverlight, ASP.NET, etc. SynchronizationContext is much more suitable as an abstract "thread context" for a business layer.
Invoke on a Windows.Forms object causes the function to be invoked on a separate thread. If an Exception is thrown in your invoked function, the Exception is caught and a new TargetInvocationException is thrown.
This TargetInvocationException contains the initial Excpetion in it's InnerException property.
So, try to do it this way:
catch (TargetInvocationException ex) { MSASession.ErrorLogger.Log(ex.InnerException); }
Edit: Also, if you expand the InnerException property in the debugger, you will be able to access it's stacktrace, even if only as plain text.
Related
I'm trying to handle errors that are passed through 2 dlls I've created. So Console.exe calls dll 1. dll 1 completes an async MQ message read and the handler calls dll 2. If dll 2 errors it passes the Exception (throw) without a problem. But the dll 1 (async) handler catch the throw from dll 2 and give me an unhandled by user message.. I have followed the msdn code to add in the IAsyncResult to keep the hander alive but the issue persists.
can anyone advise on how I should handle this stack and get the handler error returned to the console.exe program so I can present it to the user. Code below:-
Console.exe (snippet)
try
{
_msmq.MSMQ_GetMessage(_msgPath);
//set up the print of the number of queue messages
Console.WriteLine("Main thread: starting a timer");
Timer t = new Timer(ComputeBoundOp, _msgPath, 0, 2000);
Console.Write("Press any key to continue . . .");
Console.ReadKey(true);
t.Dispose(); // Cancel the timer now
}
catch (MessageQueueException _msgQex)
{
Console.WriteLine("An error occurred with the queue:- " + _msgQex);
}
catch (Exception _ex)
{
Console.WriteLine("An error occurred with the queue:- " + _ex);
}
dll 1
public void MSMQ_GetMessage(string _MQ_Path)
{
try
{
//set the correct message queue
MessageQueue _msgQ = new MessageQueue(_MQ_Path, QueueAccessMode.ReceiveAndAdmin);
//set the format of the message queue
_msgQ.Formatter = new XmlMessageFormatter(new Type[] { typeof(_TwitterStreamFeed) });
_msgQ.ReceiveCompleted += new ReceiveCompletedEventHandler(_msgQ_RecieveCompleted);
IAsyncResult _result = _msgQ.BeginReceive();
_asyncList.Add(_result); // asyncList is a global variable of type System.Collections - > this allows the callback to remain open and therefore nit garbage collected while the async thread runs off on it's own
}
catch (Exception _ex)
{
throw new Exception("_msgQ_get Message threw the following error :- " + _ex);
}
}
//method to process message
public void _msgQ_RecieveCompleted(object sender, ReceiveCompletedEventArgs e)
{
try
{
//queue that have received a message
MessageQueue _mq = (MessageQueue)sender;
//get the messge off the queue
Message _mqmsg = _mq.EndReceive(e.AsyncResult);
//set the values back into a formatted struct
//now process your SQL....
Azure_SQL _azuresql = new Azure_SQL();
_azuresql.writeMessageToStorage((_TwitterStreamFeed)_mqmsg.Body);
//refresh queue just in case any changes occurred (optional)
_mq.Refresh();
//tell MessageQueue to receive next message when it arrives
_mq.BeginReceive();
}
catch (Exception _ex)
{
throw;
}
dll 2
public void writeMessageToStorage(_TwitterStreamFeed _msmq_message_as_TSF)
{
try
{
// now do something with the class - i..e write the values to the database
SqlConnection _azurecon = new SqlConnection(_AzuzeSQLConnection);
SqlCommand _sqlcmd = new SqlCommand();
//Setup the command string to call the stored procedure
//Add the parameter to the parameters collection of the command
blah blah blah......... Do SQL writing to Db
_azurecon.Open();
SqlDataReader _sqldr_tweet_place = _sqlcmd_place.ExecuteReader(CommandBehavior.CloseConnection);
}
//now close things off
_azurecon.Close();
}
catch (Exception _ex)
{
// Throw the error to preserve the original
throw;
}
The reason for this is that, internally, the MessageQueue class is explicitly swallowing the exception. Where the MessageQueue class raises the ReceiveCompleted event, it's inside of a try-catch statement - and the catch block is empty. Suffice it to say, if an exception occurs inside your ReceiveCompleted event handler, _msgQ_RecieveCompleted(), nothing's ever going to know it happened.
I see a couple of options, in order of preference.
Option 1 - Shift where the asynchronous call is made
Since this exception-swallowing behavior only occurs when using BeginReceive(), in MSMQ_GetMessage(), you can switch from using BeginReceive() to just Receive(). Then, make your call to MSMQ_GetMessage() asynchronous and any exception that gets thrown will be propagated as expected.
As a side note, a new(er) alternative for making asynchronous calls is available; the Task<> class. As opposed to the Thread class, Task<> has exception handling functionality built in. It does, however, require Framework 4 or higher. There is a good explanation of it's use described in the answer here.
Option 2 - Use a custom event
If refactoring the asynchronous call isn't an option, you can create a custom event in your class in 'dll 2' and subscribe to that event in 'Console.exe'. So when an exception occurs in _msgQ_RecieveCompleted(), you can raise the event and 'Console.exe' will be notified.
The MessageQueue.BeginReceive() method uses the standard .NET APM (Asynchronous Programming Model) pattern. It is very important to understand how it works to know how to properly deal with exceptions. Be sure to read the MSDN article, there are lots of other googable resources available.
In APM, the callback that tells you that a message was received in executed on a thread-pool thread. Which is a very efficient way to get code to run quickly. It is however also a very troublesome way when something goes wrong. The EndReceive() method call is likely to throw an exception, it does so to tell you that the receive operation could not be completed. A standard exception it will throw is ObjectDisposedException. Which will happen when the MessageQueue object gets disposed. In your case when your program terminates. You need to catch that exception and exit from your event handler, it is an expected exception and signals that nothing more useful is going to happen next since the queue was closed.
Then there's a raft of possible exceptions that can be raised by major mishaps in the message queue plumbing. Plus whatever you do with the message. Looks like you execute some Azure code, plenty of ways that can fall over. If you let such an exception escape from the callback method, like you do, then there's no catch clause anywhere in the call stack that is going to handle the exception. The standard way .NET deals with unhandled exceptions is to raise the AppDomain.UnhandledException event and terminate your program. If you didn't actually implement that event then there's nothing decent to look at to diagnose the reason your program ended, the Windows Error Reporting dialog has no good diagnostic.
Whether or not you should try to handle the exception and prevent the program from terminating is up to you. But it pretty strongly fits the "don't shoot the messenger" pattern, it is very unlikely your program can meaningfully continue to execute when such an exception is raised. It invariably takes a human to fix the problem, like restoring the network connection or fixing the message queue. If you do catch it then the odds that the same exception is raised over and over again is fairly likely. After all, there wasn't anything decent you could do in your code to repair the network.
So the best guidance here is to not try, just make sure that IT staff has a good diagnostic so they can repair the problem. Do implement the AppDomain.UnhandledException and display and log the e.UnhandledException.ToString() value. This will also let you learn the number of ways that your program can fail. There might be some conditions that are common enough to warrant catching, something like a temporary network outage. At that point you'll also know what to do about it, in other words what kind of code to write in the catch clause. There is no possible way you know what to write right now, you should therefore not try.
Last but not least, do note that you got yourself into this pickle because you used BeginReceive() unnecessarily. You've already got a perfectly good thread to do work on. But it doesn't do anything useful, it is stuck in the Console.ReadKey() method. Particularly in .NET 4.5 a very tricky method to call, it prevents other threads from writing anything to the console. So your error reporting won't work, it will deadlock when it tries to use Console.WriteLine() to write a diagnostic.
You might as well use MessageQueue.Read() instead. Now dealing with exceptions is a lot easier since they occur on the same thread. The MessageQueue.SynchronizingObject can also be helpful to get completion callbacks to occur on the main thread, but that only works in a GUI app, not in a console app.
Disclaimer, I'm from a Java background. I don't do much C#. There's a great deal of transfer between the two worlds, but of course there are differences and one is in the way Exceptions tend to be thought about.
I recently answered a C# question suggesting that under some circstances it's reasonable to do this:
try {
some work
} catch (Exeption e) {
commonExceptionHandler();
}
(The reasons why are immaterial). I got a response that I don't quite understand:
until .NET 4.0, it's very bad to catch
Exception. It means you catch various
low-level fatal errors and so disguise
bugs. It also means that in the event
of some kind of corruption that
triggers such an exception, any open
finally blocks on the stack will be
executed, so even if the
callExceptionReporter fuunction tries
to log and quit, it may not even get
to that point (the finally blocks may
throw again, or cause more corruption,
or delete something important from the
disk or database).
May I'm more confused than I realise, but I don't agree with some of that. Please would other folks comment.
I understand that there are many low level Exceptions we don't want to swallow. My commonExceptionHandler() function could reasonably rethrow those. This seems consistent with this answer to a related question. Which does say "Depending on your context it can be acceptable to use catch(...), providing the exception is re-thrown." So I conclude using catch (Exception ) is not always evil, silently swallowing certain exceptions is.
The phrase "Until .NET 4 it is very bad to Catch Exception" What changes in .NET 4? IS this a reference to AggregateException, which may give us some new things to do with exceptions we catch, but I don't think changes the fundamental "don't swallow" rule.
The next phrase really bothers be. Can this be right?
It also means that in the event
of some kind of corruption that
triggers such an exception, any open
finally blocks on the stack will be
executed (the finally blocks may
throw again, or cause more corruption,
or delete something important from the
disk or database)
My understanding is that if some low level code had
lowLevelMethod() {
try {
lowestLevelMethod();
} finally {
some really important stuff
}
}
and in my code I call lowLevel();
try {
lowLevel()
} catch (Exception e) {
exception handling and maybe rethrowing
}
Whether or not I catch Exception this has no effect whatever on the excution of the finally block. By the time we leave lowLevelMethod() the finally has already run. If the finally is going to do any of the bad things, such as corrupt my disk, then it will do so. My catching the Exception made no difference. If It reaches my Exception block I need to do the right thing, but I can't be the cause of dmis-executing finallys
For the question #2:
The author meant "Corrupted State Exceptions". They will be introduced in .NET 4.0 (CLR team announced this at PDC 2008 in this talk).
Corrupted state exceptions cannot be caught by normal catch block. Examples: Access violation, Invalid Memory.
But you might want to catch these exceptions:
In main() – write to log, exit, turn off addin
Very rare cases when you know that code throws exception like this (e.g. some cases with interop with native code)
To do this you should put attribute [HandleProcessCorruptedStateException] at the method where you want to catch CorruptedStateException.
To read more about these exceptions please see this MSDN article.
As a general rule you shouldn't catch exceptions unless:
You have a specific exception that you can handle and do something about. However in this case you should always check whether you shouldn't be trying to account for and avoid the exception in the first place.
You are at the top level of an application (for instance the UI) and do not want the default behaviour to be presented to the user. For instance you might want an error dialog with a "please send us your logs" style message.
You re-throw the exception after dealing with it somehow, for instance if you roll back a DB transaction.
Your finally blocks always execute. Your code sample is correct - the low level method should just have try and finally. For instance an unmanaged call might know that it needs to dispose of the unmanaged resource, but this wouldn't be exposed to .Net methods calling it. That call should get rid of the unmanaged resource in its finally block, and calling managed methods can handle exceptions or just pass them on up.
If there's something in an exception that you need to handle you should re-throw the exception, for instance:
try {
conn.BeginTransaction();
//do stuff
conn.CommitTransaction();
}
catch (Exception) {
conn.RollbackTransaction(); //required action on any exception
throw; //re-throw, don't wrap a new ex to keep the stack trace
}
finally {
conn.Dispose(); //always dispose of the resource
}
My motto is handle what you can (or need to) and let any other exceptions bubble up and catch them in an UnhandledException event.
You are correct tho, a finally block is always called (even in the event of an exception being raised in the try section) before you exit the method. So whether you want to the catch the exception on the out method or not is entirely up to you.....this should not affect the finally block being called.
Just to your third question:
If you have
nastyLowLevel() {
doSomethingWhichMayCorruptSomethingAndThrowsException();
}
MyEvilCatcher() {
try {
nastyLowLevel();
} catch (Exception e) {
MyExceptionHandler(e);
}
}
WiseCatcher() {
try {
MyEvilCatcher();
} catch (LowLevelException e) {
DoSomethingWiseSoFinnalyDontRuinAnything();
} finally {
DoSomethingWhichAssumesLowLevelWentOk();
}
}
I think the response you asked about just meant that some low level methods could use exceptions to inform some outer method that special care has to be taken. If you forget about this exceptions in your catch-all-handler and don't rethrow them, something might go wrong.
Generally, I prefer thinking carefully about which exceptions can possibly be thrown and catch them explicitely. I only use "generic handler" at the very outer level in production environments in order to log unexpected exception and present them to the customer in an well-formatted manner (including a hint to send us the log file.)
I think the quoted response is wrong (or maybe meant 2.0 instead of 4.0)? It sounds kinda bogus to me.
In an application I work on, any business logic error causes an exception to be thrown, and the calling code handles the exception. This pattern is used throughout the application and works well.
I have a situation where I will be attempting to execute a number of business tasks from inside the business layer. The requirement for this is that a failure of one task should not cause the process to terminate. Other tasks should still be able to execute. In other words, this is not an atomic operation. The problem I have is that at the end of the operation, I wish to notify the calling code that an exception or exceptions did occur by throwing an exception. Consider the following psuedo-code snippet:
function DoTasks(MyTask[] taskList)
{
foreach(MyTask task in taskList)
{
try
{
DoTask(task);
}
catch(Exception ex)
{
log.add(ex);
}
}
//I want to throw something here if any exception occurred
}
What do I throw? I have encountered this pattern before in my career. In the past I have kept a list of all exceptions, then thrown an exception that contains all the caught exceptions. This doesn't seem like the most elegant approach. Its important to preserve as many details as possible from each exception to present to the calling code.
Thoughts?
Edit: The solution must be written in .Net 3.5. I cannot use any beta libraries, or the AggregateException in .Net 4.0 as mentioned by Bradley Grainger (below) would be a nice solution for collection exceptions to throw.
The Task Parallel Library extensions for .NET (which will become part of .NET 4.0) follow the pattern suggested in other answers: collecting all exceptions that have been thrown into an AggregateException class.
By always throwing the same type (whether there is one exception from the child work, or many), the calling code that handles the exception is easier to write.
In the .NET 4.0 CTP, AggregateException has a public constructor (that takes IEnumerable<Exception>); it may be a good choice for your application.
If you're targeting .NET 3.5, consider cloning the parts of the System.Threading.AggregateException class that you need in your own code, e.g., some of the constructors and the InnerExceptions property. (You can place your clone in the System.Threading namespace inside your assembly, which could cause confusion if you exposed it publicly, but will make upgrading to 4.0 easier later on.) When .NET 4.0 is released, you should be able to “upgrade” to the Framework type by deleting the source file containing your clone from your project, changing the project to target the new framework version, and rebuilding. Of course, if you do this, you need to carefully track changes to this class as Microsoft releases new CTPs, so that your code doesn't become incompatible. (For example, this seems like a useful general-purpose class, and they could move it from System.Threading to System.) In the worst case, you can just rename the type and move it back into your own namespace (this is very easy with most refactoring tools).
Two ways of the top of my head would be either make a custom exception and add the exceptions to this class and throw that the end :
public class TaskExceptionList : Exception
{
public List<Exception> TaskExceptions { get; set; }
public TaskExceptionList()
{
TaskExceptions = new List<Exception>();
}
}
public void DoTasks(MyTask[] taskList)
{
TaskExceptionList log = new TaskExceptionList();
foreach (MyTask task in taskList)
{
try
{
DoTask(task);
}
catch (Exception ex)
{
log.TaskExceptions.Add(ex);
}
}
if (log.TaskExceptions.Count > 0)
{
throw log;
}
}
or return true or false if the tasks failed and have a 'out List' variable.
public bool TryDoTasks(MyTask[] taskList, out List<Exception> exceptions)
{
exceptions = new List<Exception>();
foreach (MyTask task in taskList)
{
try
{
DoTask(task);
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
if (exceptions.Count > 0)
{
return false;
}
else
{
exceptions = null;
return true;
}
}
You could create a custom Exception that itself has a collection of Exceptions. Then, in your Catch block, just add it to that collection. At the end of your process, check if the Exception count is > 0, then throw your custom Exception.
You might want to use a BackgroundWorker to do this for you. It automatically captures and presents any exceptions when completed, which you could then throw or log or do whatever with. Also, you get the benefit of multithreading.
The BackgroundWorker is a nice wrapper around delegate's asynchronous programming model.
No super-elegant solution here but a few ideas:
Pass an error-handler function as argument to DoTasks so the user can decide whether to continue
Use tracing to log errors as they occur
Concatenate the messages from the other exceptions in the exception bundle's message
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.
The code that I want to write is like this:
void MethodOnThreadA()
{
for (;;)
{
// Do stuff
if (ErrorConditionMet)
ThrowOnThread(threadB, new MyException(...));
}
}
void MethodOnThreadB()
{
try
{
for (;;)
{
// Do stuff
}
}
catch (MyException ex)
{
// Do the right thing for this exception.
}
}
I know I can have thread B periodically check, in thread safe way, to see if a flag has been set by thread A, but that makes the code more complicated. Is there a better mechanism that I can use?
Here is a more fleshed out example of periodically checking:
Dictionary<Thread, Exception> exceptionDictionary = new Dictionary<Thread, Exception>();
void ThrowOnThread(Thread thread, Exception ex)
{
// the exception passed in is going to be handed off to another thread,
// so it needs to be thread safe.
lock (exceptionDictionary)
{
exceptionDictionary[thread] = ex;
}
}
void ExceptionCheck()
{
lock (exceptionDictionary)
{
Exception ex;
if (exceptionDictionary.TryGetValue(Thread.CurrentThread, out ex))
throw ex;
}
}
void MethodOnThreadA()
{
for (;;)
{
// Do stuff
if (ErrorConditionMet)
ThrowOnThread(threadB, new MyException(...));
}
}
void MethodOnThreadB()
{
try
{
for (;;)
{
// Do stuff
ExceptionCheck();
}
}
catch (MyException ex)
{
// Do the right thing for this exception.
}
}
This is NOT a good idea
This article talks about ruby's timeout library. which throws exceptions across threads.
It explains how doing such a thing is fundamentally broken. It's not just broken in ruby, it's broken anywhere that throws exceptions across threads.
In a nutshell, what can (and does) happen is this:
ThreadA:
At some random time, throw an exception on thread B:
ThreadB:
try {
//do stuff
} finally {
CloseResourceOne();
// ThreadA's exception gets thrown NOW, in the middle
// of our finally block and resource two NEVER gets closed.
// Obviously this is BAD, and the only way to stop is to NOT throw
// exceptions across threads
CloseResourceTwo();
}
Your 'periodic checking' example is fine, as you're not actually throwing exceptions across threads.
You're just setting a flag which says "throw an exception the next time you look at this flag", which is fine as it doesn't suffer from the "can be thrown in the middle of your catch or finally block" problem.
However, if you're going to do that, you may as well just be setting an "exitnow" flag, and using that and save yourself the hassle of creating the exception object. A volatile bool will work just fine for that.
There are enough problems with exceptions that can be thrown on threads by other mechanisms, like aborting threads and the likes, that you should find another way of doing it.
An exception is a mechanism used to signal that a process has experienced something exceptional that it cannot deal with. You should try to avoid writing the code so that an exception is used to signal that something else has experienced something exceptional.
That other thread will most likely not know how to handle the exception in all cases where it could be thrown by your code.
In short, you should find some other mechanism for aborting your threads than using exceptions.
Use event objects or similar to tell a thread to abort its processing, that's the best way.
What Orion Edwards is saying is not entirely true: is not the "only" way.
// Obviously this is BAD, and the only way to stop is to NOT throw
// exceptions across threads
Using CER (Constrained Execution Regions) in C# allows you to release your resources as an atomic operation, protecting your code from inter-thread exceptions. This technique is used by several classes of the .NET Framework which work with Windows' native API, where an unreleased handle may cause a memory leak.
See http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx
The following example shows how to reliably set handles by using the PrepareConstrainedRegions method. To reliably set a handle to a specified pre-existing handle, you must ensure that the allocation of the native handle and the subsequent recording of that handle within a SafeHandle object is atomic. Any failure between these operations (such as a thread abort or out-of-memory exception) will result in the native handle being leaked. You can use the PrepareConstrainedRegions method to make sure that the handle is not leaked.
As simple as:
public MySafeHandle AllocateHandle()
{
// Allocate SafeHandle first to avoid failure later.
MySafeHandle sh = new MySafeHandle();
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally // this finally block is atomic an uninterruptible by inter-thread exceptions
{
MyStruct myStruct = new MyStruct();
NativeAllocateHandle(ref myStruct);
sh.SetHandle(myStruct.m_outputHandle);
}
return sh;
}
While researching another issue, I came across this article which reminded me of your question:
Plumbing the Depths of the ThreadAbortException using Rotor
It shows the gyrations that .NET goes through to implement Thread.Abort() -- presumably any other cross-thread exception would have to be similar. (Yeech!)
I'm interested to know why you would want to do this. There's not an easy way to do it, because it's not a good practice. You should probably go back to your design and figure out a cleaner way to accomplish the end goal.
I don't think that's a good idea..
Take another crack at this problem - Try using some other mechanism like shared data to signal between threads.
Like the others, I'm not sure that's such a good idea, but if you really want to do it, then you can create a subclass of SynchronizationContext that allows posting and sending delegates to the target thread (if it's a WinForms thread the work is done for you as such a subclass already exists). The target thread will have to implement some sort of a message pump equivalent though, to receive the delegates.
#Orion Edwards
I take your point about an exception being thrown in the finally block.
However, I think there is a way - using yet another thread - of using this exception-as-interrupt idea.
Thread A:
At some random time, throw an exception on thread C:
Thread B:
try {
Signal thread C that exceptions may be thrown
//do stuff, without needing to check exit conditions
Signal thread C that exceptions may no longer be thrown
}
catch {
// exception/interrupt occurred handle...
}
finally {
// ...and clean up
CloseResourceOne();
CloseResourceTwo();
}
Thread C:
while(thread-B-wants-exceptions) {
try {
Thread.Sleep(1)
}
catch {
// exception was thrown...
if Thread B still wants to handle exceptions
throw-in-B
}
}
Or is that just silly?