c# - traduccion - ¿Debería usar tanto AppDomain.UnhandledException como Application.DispatcherUnhandledException?
unhandled exception solucion (2)
Después de leer algunas publicaciones excelentes sobre la diferencia entre AppDomain.UnhandledException y Application.DispatcherUnhandledException, parece que debería manejar ambas. Esto se debe a que es mucho más probable que el usuario pueda recuperarse de una excepción generada por el subproceso de la interfaz de usuario principal (es decir, Application.DispatcherUnhandledException). ¿Correcto?
Además, ¿debería dar también al usuario la oportunidad de continuar con el programa para ambos, o solo la aplicación.DispatcherUnhandledException?
El código de ejemplo a continuación controla tanto AppDomain.UnhandledException como Application.DispatcherUnhandledException, y ambos le dan al usuario la opción de intentar continuar a pesar de la excepción.
[Gracias y parte del código de abajo se elimina de otras respuestas]
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 [redactado]
/// <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./n/nError:{0}/n/nDo 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./n/nError:{0}/n/nDo 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;
}
Un controlador AppDomain.UnhandledException
está conectado como:
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Pero no pude encontrar una manera de marcar como se maneja en el controlador, por lo que esto siempre parece hacer que una aplicación se cierre sin importar lo que hagas. Así que no creo que esto sea de mucha utilidad.
Es mejor manejar Application.Current.DispatcherUnhandledException
y probar CommunicationObjectFaultedException
, ya que puede recuperarse de eso simplemente reiniciando su proxy, exactamente como lo hizo en la conexión inicial. P.ej:
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();
}
donde Initialize tiene su instancia de proxy inicial / código de conexión.
En el código que publicó anteriormente, sospecho que está manejando DispatcherUnhandledException
dos veces , al cablear un controlador en xaml Y en el código.
-
AppDomain.CurrentDomain.UnhandledException
en teoría captura todas las excepciones en todos los subprocesos del dominio de la aplicación. Sin embargo, encontré que esto es muy poco confiable. Application.Current.DispatcherUnhandledException
captura todas las excepciones en el subproceso de la interfaz de usuario. Esto parece funcionar de manera confiable y reemplazará al controladorAppDomain.CurrentDomain.UnhandledException
en el subproceso de la interfaz de usuario (tiene prioridad). Usee.Handled = true
para mantener la aplicación en ejecución.Para detectar excepciones en otros subprocesos (en el mejor de los casos, se manejan en su propio subproceso), encontré que System.Threading.Tasks.Task (solo .NET 4.0 y superior) es de bajo mantenimiento. Manejar excepciones en tareas con el método
.ContinueWith(...,TaskContinuationOptions.OnlyOnFaulted)
. Vea mi respuesta here para más detalles.