Joey
Joey

Reputation: 354516

Globally catch exceptions in a WPF application?

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:

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.

Upvotes: 285

Views: 141948

Answers (7)

Bahman Pourgholami
Bahman Pourgholami

Reputation: 23

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>

Upvotes: 3

Huseyin Yagli
Huseyin Yagli

Reputation: 10285

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);
        }
    }

Upvotes: 130

Hertzel Guinness
Hertzel Guinness

Reputation: 5950

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.

Upvotes: 20

NoWar
NoWar

Reputation: 37633

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);
        }        
    }


}

Upvotes: 4

CharithJ
CharithJ

Reputation: 47530

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.

Upvotes: 33

David Schmitt
David Schmitt

Reputation: 59346

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.

Upvotes: 213

BobbyShaftoe
BobbyShaftoe

Reputation: 28499

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.

Upvotes: -3

Related Questions