UnhandledException not called when exception thrown in another thread - c#

According to the Microsoft documentation, when an unhandled exception occurs on a thread (from either the thread pool or created using the System.Threading.Thread class) the AppDomain.UnhandledException event should fire for the default AppDomain of the application. Here is the MSDN link which explains it after the second NOTE section.
But I cannot reproduce this behaviour, as far as I can tell from my test application it never fires the UnhandledException on either the default AppDomain or the AppDomain used to create the thread. Is the documentation wrong or my testing code?
using System;
using System.Runtime.ExceptionServices;
using System.Reflection;
public class Program
{
static void Main()
{
Program.HookAppDomainExceptions();
Test t = CreateTestInsideAppDomain("Nested1");
t.SetupNested1();
Console.ReadLine();
}
public static Test CreateTestInsideAppDomain(string appDomainName)
{
AppDomain nested1 = AppDomain.CreateDomain(appDomainName);
string executingName = Assembly.GetExecutingAssembly().FullName;
return (Test)nested1.CreateInstanceAndUnwrap(executingName, "Test");
}
public static void HookAppDomainExceptions()
{
AppDomain.CurrentDomain.FirstChanceException +=
new EventHandler<FirstChanceExceptionEventArgs>(FirstChanceException);
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
public static void FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
Console.WriteLine("Domain:{0} FirstChanceException Handler",
AppDomain.CurrentDomain.FriendlyName);
}
public static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine("Domain:{0} UnhandledException Handler",
AppDomain.CurrentDomain.FriendlyName);
}
}
public class Test : MarshalByRefObject
{
private delegate void Nothing();
public void SetupNested1()
{
var start = new Nothing(Nested1ThreadStart);
start.BeginInvoke(null, null);
}
static void Nested1ThreadStart()
{
Program.HookAppDomainExceptions();
Test t = Program.CreateTestInsideAppDomain("Nested2");
t.SetupNested2();
}
public void SetupNested2()
{
Program.HookAppDomainExceptions();
Test t = Program.CreateTestInsideAppDomain("Nested3");
t.ThrowException();
}
public void ThrowException()
{
Program.HookAppDomainExceptions();
throw new ApplicationException("Raise Exception");
}
}

In your code UnhandledException isn't fired on any AppDomain, because if you call a delegate using BeginInvoke(), any exception that is thrown during its execution is handled and then rethrown when you call EndInvoke(), which you don't.
If you either call EndInvoke():
start.EndInvoke(start.BeginInvoke(null, null));
or execute the delegate synchronously:
start();
You get similar results: UnhandledException of the main domain is raised.
If instead, you do what the documentation says and start a new thread using the Thread class:
new Thread(Nested1ThreadStart).Start();
UnhandledException of Nested1 and the main app domain are raised.
So, to answer your question: The documentation is right. Your code is wrong. When you call delegate asynchronously using BeginInvoke(), you should always call EndInvoke() later.

I had this problem too. I used Observer Pattern to solve that.
you can implement an interface in your caller class that have a method which call from the other thread when an exception occurs.
Here's a link that shows how to implement this pattern Exploring the Observer Design Pattern

Related

How to make C# unit test fail if child threads throw exceptions?

I have a multi-threaded class which throws an exception in a child thread:
public class TestClass
{
private Thread theThread;
private string failString = string.Empty;
private CancellationTokenSource cancelToken;
public void OnStart()
{
cancelToken = new CancellationTokenSource();
theThread = new Thread(() => ThreadOperation(cancelToken.Token));
theThread.Start();
}
private void ThreadOperation(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
if(failString[0] == ',')
{
Console.WriteLine("Foo");
}
Thread.Sleep(10);
}
}
public void OnStop()
{
cancelToken.Cancel();
theThread.Join();
}
}
And I want to write a unit test that catches the exception and fails in that case.
But a simple unit test trying to catch the exception fails only in Debug:
[TestMethod]
public void TestException()
{
TestClass testClass = new TestClass();
testClass.OnStart();
Thread.Sleep(1000);
testClass.OnStop();
}
If I just run this test (without debugging), it passes successfully (which is not the behavior I want to achieve).
I've tried this but it doesn't fail either:
[TestMethod]
public void TestException()
{
try
{
TestClass testClass = new TestClass();
testClass.OnStart();
Thread.Sleep(1000);
testClass.OnStop();
}
catch(Exception)
{
Assert.Fail();
}
}
Is there any way to catch the exceptions of all threads (including children) and make the test fail in that case without rewriting the original class?
Normally unhandled exceptions should cause the application to terminate. There is an unhandled exception handler that can be used as a last chance to catch exception that occurs on worker threads. But this is a global exception handler so not suitable for changing by individual tests, and the unit test framework might already have attached a handler to this.
I would suggest changing from using Thread to using a Task with the LongRunning flag. This automatically captures exceptions and you can let OnStop to either return the task, or Wait on the task. The later should throw an AggregateException if any exception was encountered.
An alternative would be to manually insert a try/catch in ThreadOperation and save the exception so it can be reported back when OnStop is called.

Exception throw behavior

So I have this exception I want to throw if something goes wrong. But it acts strange.
public Calendar LoadCalendar(){
...
if (cal == null)
{
throw new NotImplementedException();
}
_lastPollTime = DateTime.Now;
...
}
I expect this exception to be thrown to wherever LoadCalendar was called. Instead, the program stops at DateTime.Now; because of "NotImplementedException()".
What am I doing wrong? How could I throw it to the end of the method instead?
You need to add a "catch" clause somewhere up the call stack which receives the thrown exception and deals with it somehow.
You could try this in your programs Main function:
static void Main()
{
try
{
// put existing code here
}
catch( Exception e )
{
}
}
Without a catch, the exception has no place to go to and so instead it causes your program to terminate.
These guidlines for working with exceptions might be useful to you: http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET
Just subscribe DispatcherUnhandledException event in App.xaml.cs Class Constructor and you can handle any application exception in this event.
public partial class App : Application
{
public App()
{
this.DispatcherUnhandledException += App_DispatcherUnhandledException;
}
void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
////Handle your application exception's here by e.Exception.
}
}

A global error handler for a class library in C#

Is there a way to catch and handle an exception for all exceptions thrown within any of the methods of a class library?
I can use a try catch construct within each method as in sample code below, but I was looking for a global error handler for a class library. The library could be used by ASP.Net or Winforms apps or another class library.
The benefit would be easier development, and no need to repeatedly do the same thing within each method.
public void RegisterEmployee(int employeeId)
{
try
{
....
}
catch(Exception ex)
{
ABC.Logger.Log(ex);
throw;
}
}
You can subscribe to global event handler like AppDomain.UnhandledException and check the method that throws exception:
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
{
var exceptionObject = unhandledExceptionEventArgs.ExceptionObject as Exception;
if (exceptionObject == null) return;
var assembly = exceptionObject.TargetSite.DeclaringType.Assembly;
if (assembly == //your code)
{
//Do something
}
}

Why exception in child domain close program?

Why exception in one application domain affect another application domain?
How do I prevent the closing of the program?
using System;
using System.Reflection;
using System.Threading;
namespace domain
{
public class Worker : MarshalByRefObject
{
public static void NotMyCodeThreadProc()
{
throw new Exception();
}
public void NotMyCode()
{
var thread = new Thread(NotMyCodeThreadProc);
thread.Start();
thread.Join();
}
}
class Program
{
static void Main()
{
AppDomain ad = AppDomain.CreateDomain("New domain");
Worker remoteWorker = (Worker) ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "domain.Worker");
try
{
remoteWorker.NotMyCode();
}
catch
{
}
Console.WriteLine("!");
Console.ReadLine();
}
}
}
In .NET 2.0 (and above), an unhandled exception in a thread causes the entire process to terminate.
You can change that policy by following Hans' advice, or you can simply wrap your code with try/catch and handle the exception.

How do I get the Exception that happens in Timer Elapsed event?

I'm working with Windows Forms application and hava a manager class that uses System.Timers.Timer to periodly check data from database.
How do I get the Exception that occurs in timer Elapsed eventhandler delivered into main application? If I'm using the code below, the exception get's "swallowed", and main application never gets it (even if I have handlers for ThreadException and UnHandledException).
// Main Form
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
// Manager class
private System.Timers.Timer _timer;
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
doSomeDatabaseActions();
}
catch (Exception ex)
{
throw new ApplicationException("How do I get this error back into main thread...", ex);
}
}
If you don't have access to the main thread, you can throw the exception on another, non-timer thread:
catch (Exception exception)
{
ThreadPool.QueueUserWorkItem(
_ => { throw new Exception("Exception on timer.", exception); });
}
Since System.Timers.Timer swallows any exception thrown in the event handler, you will need to marshal the exception to another thread (probably the UI thread). You could do this via Control.Invoke, or by storing error information in a member variable and having the UI thread check this error information after the operation is complete. If non-null, the UI could then throw.
From MSDN:
In the .NET Framework version 2.0 and
earlier, the Timer component catches
and suppresses all exceptions thrown
by event handlers for the Elapsed
event. This behavior is subject to
change in future releases of the .NET
Framework.
Just checked in .NET 4.0, and this behavior has not yet changed.
You can assign the exception to a local variable and check if an exception has been thrown:
// Main Form
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
// Manager class
private System.Timers.Timer _timer;
private exception = null;
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
//reset the exception in case object is reused.
this.exception = null;
try
{
doSomeDatabaseActions();
}
catch (Exception ex)
{
this.exception = ex;
}
}
/**
* Checks whether the exception object is set.
*/
public bool hasExceptionOccured(){
return (this.exception != null);
}
//The main application will call this to get the exception.
public Exception getException(){
return this.exception;
}
I guess that you want to handle the exception on the main form, this solution is not complete but shows how to do it with an "Action"
using System;
using System.Timers;
public class MainForm
{
public MainForm()
{
var tm = new TestManager(exception =>
{
//do somthing with exception
//note you are still on the timer event thread
});
}
}
public class TestManager
{
private readonly Action<Exception> _onException;
public TestManager(System.Action<System.Exception> onException )
{
_onException = onException;
}
private System.Timers.Timer _timer;
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
doSomeDatabaseActions();
}
catch (Exception ex)
{
//throw new ApplicationException("How do I get this error back into main thread...", ex);
_onException(ex);
}
}
}

Categories

Resources