0

I have coded this inside App startup

inside App.xaml.cs

public App()
{
    AppDomain currentDomain = AppDomain.CurrentDomain;

    currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);

    DispatcherUnhandledException += App_DispatcherUnhandledException;

    Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(Application_DispatcherUnhandledException);

    TaskScheduler.UnobservedTaskException += new EventHandler<UnobservedTaskExceptionEventArgs>(Application_DispatcherUnhandledException2);

    this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;


}

private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    writeMessage(e.Exception);
}

private void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    writeMessage(e.Exception);
}

private static void writeMessage(Exception e)
{
    string srMsg = e.InnerException?.Message;

    if (srMsg != null)
    {
        srMsg += "\r\n\r\nStack\r\n" + e.InnerException?.StackTrace;
    }

    if (srMsg == null)
    {
        srMsg = e.Message + "\r\n\r\nStack\r\n" + e.StackTrace;
    }

    srMsg += "\r\n\r\n*********\r\n\r\n";

    File.AppendAllText("global_errors.txt", srMsg);

}

private static void Application_DispatcherUnhandledException2(object o, UnobservedTaskExceptionEventArgs e)
{
    writeMessage(e.Exception);
}

private static void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
    writeMessage(e.Exception);
}

private static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
    Exception e = (Exception)args.ExceptionObject;
    writeMessage(e);
}

However, this is still not capturing task factory errors

For example

enter image description here

enter image description here

enter image description here

enter image description here

Nothing proposed in this thread works WPF global exception handler

Furkan Gözükara
  • 22,964
  • 77
  • 205
  • 342
  • It's not an unhandled exception though. The Task wrapper catches and holds the exception. You could try changing the signature of your button click to `private async void Button_Click` and then doing `await Task.Run(() => test.Example(););`. Can't test it here though, so not sure if it'll work. Note here that, unless some specific cases, `Task.Run` is the replacement of `TaskFactory.StartNew`: https://devblogs.microsoft.com/pfxteam/task-run-vs-task-factory-startnew/ –  Feb 10 '20 at 12:18
  • Did you take a look at the [AppDomain.FirstChanceException](https://learn.microsoft.com/en-us/dotnet/api/system.appdomain.firstchanceexception?view=netframework-4.8) event? I successfully catched 'unhanded exceptions' in any threads with it in the past. The only drawback is, that you will get **any** thrown error, no matter if you are using a try and catch or not. – Twenty Feb 10 '20 at 12:19
  • @Knoop adding wait surely fixes problem but then my screen becomes unresponsive because it locks the main thread – Furkan Gözükara Feb 10 '20 at 12:21
  • @Twenty it captures the error but i cant see why error happened. Input string was not in a correct format. Stack at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal). it shows message bu not the stack trace – Furkan Gözükara Feb 10 '20 at 12:24
  • Mhh, I just tested it on my own and I get the StackTrace along with the `FirstChanceExceptionEventArgs`. Are you sure that `e.Exception.StackTrace` is null? – Twenty Feb 10 '20 at 12:28
  • @Twenty not null but do not provide useful information as well. shows generic class like at System.Linq.Enumerable.First[TSource](IEnumerable`1 source) – Furkan Gözükara Feb 10 '20 at 12:42
  • @Twenty and another not null stacktrace. but there is no other one at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal) – Furkan Gözükara Feb 10 '20 at 12:47
  • What about using `StackTrace`, I managed to get the full `StackTrace`, `var st = new StackTrace(); var frames = st.GetFrames();`. Try to give it a shot. – Twenty Feb 10 '20 at 12:53
  • @Twenty still i could not get the error happened line. how did you manage? perhaps you can post a full answer – Furkan Gözükara Feb 10 '20 at 13:10
  • Seems like best solution is garbage collecting on application exit. or periodically garbage collecting. – Furkan Gözükara Feb 10 '20 at 13:12

2 Answers2

2

The exception is thrown only if you observe the Task by for example calling Wait() or .Result or accessing its Exception property.

Unobserved exceptions are not thrown unless you use the <ThrowUnobservedTaskExceptions> configuration element to revert back to the behavior that was the default in .NET Framework 4 and terminates the process:

<runtime>
  <ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>

If you really want to catch the exception, you should do it in the delegate that you pass to Task.Factory.StartNew. You may wrap this functionality in an extension method as suggested here.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • it has a nice question "This will require to add .Catch<> block to every invocation of Task.Run? Is there a way to auto-add it to all invocations?" if i have to write for every task it is not global :D – Furkan Gözükara Feb 10 '20 at 12:43
  • Also adding changes nothing :/ – Furkan Gözükara Feb 10 '20 at 12:44
  • @MonsterMMORPG: Yes, it does. The event handler for `TaskScheduler.UnobservedTaskException` is invoked when the unobserved task is collected. – mm8 Feb 10 '20 at 12:49
  • The garbage collection of the faulted task is not deterministic. It may happen after short or long time. Unless you call `GC.Collect()` explicitly in your code. – Theodor Zoulias Feb 10 '20 at 13:36
2

Getting the StackTrace can be done in several ways, it really depends on what fits your needs the best. Anyhow I would suggest you, to try the following.

  1. Add a callback to the AppDomain.FirstChanceException event, at the start of your project e.g. before the errors occur which you want to catch/log. This could look something like the following:
public static Main()
{
    AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;
}

private static void CurrentDomain_FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{

}
  1. After that, add the Environment.StackTrace in the CurrentDomain_FirstChanceException method. It will hold the current StackTrace as a string. From my testing it includes the FileName and FileLineNumber.
var currentStackTrace = Environment.StackTrace;

// Now it is on to you on what you want to do with the StackTrace. This could be some kind of logging.

Note that this will log ALL exceptions thrown by the AppDomain, no matter if they are handled by the code e.g. try/catch.

Twenty
  • 5,234
  • 4
  • 32
  • 67
  • 1 more thing. i see that this will catch try/catch handled ones as well. are there any way to know whether exception was gracefully handled or not? so that i would not log it – Furkan Gözükara Feb 11 '20 at 07:27
  • Sadly you **can't** do that as I said in the answer. As the name suggests `FirstChanceException` it will get executed at the very first moment that an exception gets thrown, even before a `try/catch`. What you could do, is creating some sort of custom logging which would allow your application to tell the logger that a certain error got handled. For example by calling a method each time you hit an exception and a `try/catch` handles it. – Twenty Feb 11 '20 at 12:19