Devrait utiliser les deux AppDomain.UnhandledException et de l'Application.DispatcherUnhandledException?

après avoir lu quelques excellents billets sur la différence entre AppDomain.UnhandledException et de l'Application.DispatcherUnhandledException, il semble que je dois être la manipulation à la fois. C'est parce qu'il est beaucoup plus probable que l'utilisateur peut récupérer d'une exception lancée par le thread principal D'UI (i.e., Application.DispatcherUnhandledException). - Il Correct?

aussi, devrais-je aussi donner à l'utilisateur une chance de continuer le programme pour les deux, ou juste le Application.DispatcherUnhandledException?

exemple de code ci-dessous traite les deux Appdomaines.UnhandledException et de l'Application.DispatcherUnhandledException, et à la fois donner à l'utilisateur la possibilité d'essayer de continuer en dépit de l'exception.

[merci et certains le code ci-dessous est levé à partir d'autres réponses]

App.xaml

<Application x:Class="MyProgram.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Startup="App_StartupUriEventHandler"
         Exit="App_ExitEventHandler"
         DispatcherUnhandledException="AppUI_DispatcherUnhandledException">
    <Application.Resources>
    </Application.Resources>
</Application>

App.XAML.cs [rédigé]

/// <summary>
/// Add dispatcher for Appdomain.UnhandledException
/// </summary>
public App()
    : base()
{
    this.Dispatcher.UnhandledException += OnDispatcherUnhandledException;
}

/// <summary>
/// Catch unhandled exceptions thrown on the main UI thread and allow 
/// option for user to continue program. 
/// The OnDispatcherUnhandledException method below for AppDomain.UnhandledException will handle all other exceptions thrown by any thread.
/// </summary>
void AppUI_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
    if (e.Exception == null)
    {
        Application.Current.Shutdown();
        return;
    }
    string errorMessage = string.Format("An application error occurred. If this error occurs again there seems to be a serious bug in the application, and you better close it.nnError:{0}nnDo you want to continue?n(if you click Yes you will continue with your work, if you click No the application will close)", e.Exception.Message);
    //insert code to log exception here
    if (MessageBox.Show(errorMessage, "Application User Interface Error", MessageBoxButton.YesNoCancel, MessageBoxImage.Error) == MessageBoxResult.No)
    {
        if (MessageBox.Show("WARNING: The application will close. Any changes will not be saved!nDo you really want to close it?", "Close the application!", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning) == MessageBoxResult.Yes)
        {
            Application.Current.Shutdown();
        }
    }
    e.Handled = true;
}

/// <summary>
/// Catch unhandled exceptions not thrown by the main UI thread.
/// The above AppUI_DispatcherUnhandledException method for DispatcherUnhandledException will only handle exceptions thrown by the main UI thread. 
/// Unhandled exceptions caught by this method typically terminate the runtime.
/// </summary>
void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
    string errorMessage = string.Format("An application error occurred. If this error occurs again there seems to be a serious bug in the application, and you better close it.nnError:{0}nnDo you want to continue?n(if you click Yes you will continue with your work, if you click No the application will close)", e.Exception.Message);
    //insert code to log exception here
    if (MessageBox.Show(errorMessage, "Application UnhandledException Error", MessageBoxButton.YesNoCancel, MessageBoxImage.Error) == MessageBoxResult.No)
    {
        if (MessageBox.Show("WARNING: The application will close. Any changes will not be saved!nDo you really want to close it?", "Close the application!", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning) == MessageBoxResult.Yes)
        {
            Application.Current.Shutdown();
        }
    }
    e.Handled = true;
}
30
demandé sur abatishchev 2012-04-08 11:50:28

2 réponses

  • AppDomain.CurrentDomain.UnhandledException en théorie capte toutes les exceptions sur tous les threads de l'appdomaine. J'ai trouvé ceci pour être très peu fiable.
  • Application.Current.DispatcherUnhandledException capture toutes les exceptions sur le thread. Cela semble fonctionner de manière fiable, et remplacera le AppDomain.CurrentDomain.UnhandledException handler sur le thread UI (prend la priorité). Utilisez e.Handled = true pour maintenir l'application en marche.

  • pour attraper des exceptions sur d'autres threads (dans le meilleur des cas, ils sont manipulés sur leur propre thread), j'ai trouvé Système.Le filetage.Tâche.Tâche (seulement .NET 4.0 et au-dessus) à faible maintenance. Gérer les exceptions dans les tâches avec la méthode .ContinueWith(...,TaskContinuationOptions.OnlyOnFaulted). Voir ma réponse ici pour plus de détails.

36
répondu Mike Fuchs 2018-09-28 09:08:26

AppDomain.UnhandledException gestionnaire est câblé comme:

AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

mais je n'ai pas pu trouver un moyen de marquer comme manipulé dans le handler - donc cela semble toujours entraîner un arrêt de l'application peu importe ce que vous faites. Donc, je ne pense pas que ce est beaucoup de l'utilisation.

Mieux gérer Application.Current.DispatcherUnhandledException et pour tester CommunicationObjectFaultedException - comme vous pouvez vous en remettre en initialisant simplement votre proxy-exactement comme vous l'avez fait lors de la connexion initiale. E. g:

void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {
    if (e.Exception is CommunicationObjectFaultedException) { //|| e.Exception is InvalidOperationException) {
        Reconnect();
        e.Handled = true;
    }
    else {
        MessageBox.Show(string.Format("An unexpected error has occured:\n{0}.\nThe application will close.", e.Exception));
        Application.Current.Shutdown();
    }
}

public bool Reconnect() {
    bool ok = false;
    MessageBoxResult result = MessageBox.Show("The connection to the server has been lost.  Try to reconnect?", "Connection lost", MessageBoxButton.YesNo);
    if (result == MessageBoxResult.Yes)
        ok = Initialize();
    if (!ok)
        Application.Current.Shutdown();
}

où Initialize a votre initiale instanciation de procuration / code de connexion.

Dans le code que vous avez posté ci-dessus, je pense que vous êtes la manipulation DispatcherUnhandledException deux fois - en câblant un handler en xaml et en code.

5
répondu Ricibob 2012-04-20 08:22:16