.NET. Какой лучший способ реализовать "catch all exceptions handler"
Мне интересно, как лучше всего иметь "если все остальное не удается поймать".
Я имею в виду, что вы обрабатываете как можно больше исключений в своем приложении,
но все еще есть ошибки, поэтому мне нужно иметь что-то, что
ловит все необработанные исключения, поэтому я могу собирать информацию и хранить
их в базе данных или отправить их в веб-службу.
Захватывает ли событие AppDomain.CurrentDomain.UnhandledException все?
Даже если приложение многопоточно?
Примечание: Windows Vista предоставляет собственные функции API, которые позволяют любому приложению
восстановить себя после крушения... теперь не могу вспомнить имя... но я бы предпочел не
используйте его, так как многие из наших пользователей все еще используют Windows XP.
Ответы
Ответ 1
Я только что играл с приложением AppDomain UnhandledException,
(это последний этап, на котором зарегистрировано необработанное исключение)
Да, после обработки обработчиков событий ваше приложение будет завершено, и отобразится отвратительная "... программа перестала работать диалог".
:)
Вы все еще можете этого избежать.
Отъезд:
class Program
{
void Run()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Console.WriteLine("Press enter to exit.");
do
{
(new Thread(delegate()
{
throw new ArgumentException("ha-ha");
})).Start();
} while (Console.ReadLine().Trim().ToLowerInvariant() == "x");
Console.WriteLine("last good-bye");
}
int r = 0;
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Interlocked.Increment(ref r);
Console.WriteLine("handled. {0}", r);
Console.WriteLine("Terminating " + e.IsTerminating.ToString());
Thread.CurrentThread.IsBackground = true;
Thread.CurrentThread.Name = "Dead thread";
while (true)
Thread.Sleep(TimeSpan.FromHours(1));
//Process.GetCurrentProcess().Kill();
}
static void Main(string[] args)
{
Console.WriteLine("...");
(new Program()).Run();
}
}
P.S. Обработайте необработанные для Application.ThreadException(WinForms) или DispatcherUnhandledException (WPF) на более высоком уровне.
Ответ 2
В ASP.NET вы используете функцию Application_Error
в файле Global.asax
.
В WinForms вы используете MyApplication_UnhandledException
в файле ApplicationEvents
Обе эти функции вызывают, если в вашем коде возникает необработанное исключение. Вы можете зарегистрировать исключение и представить пользователю хорошее сообщение из этих функций.
Ответ 3
Для приложений Winform, помимо AppDomain.CurrentDomain.UnhandledException, я также использую Application.ThreadException и Application.SetUnhandledExceptionMode (w/UnhandledExceptionMode.CatchException). Кажется, что эта комбинация ложится на все.
Ответ 4
В главном потоке у вас есть следующие опции:
Для других потоков:
- Вторичные потоки не имеют необработанных исключений; используйте SafeThread
- Рабочие потоки: (таймер, threadpool) нет никакой системы безопасности!
Помните, что эти события не обрабатывают исключения, они просто сообщают о них в приложение - часто, когда слишком поздно делать что-либо полезное/разумное о них
Исключения протоколирования хороши, но лучше контролировать приложения; -)
Предостережение: Я являюсь автором статьи SafeThread.
Ответ 5
Для WinForms не забудьте также присоединяться к текущему событию исключенного события Thread (особенно, если вы используете многопоточность).
Некоторые ссылки на лучшие практики здесь и здесь и здесь (вероятно, лучшая статья для обработки исключений для .net)
Ответ 6
Там также классная вещь, называемая ELMAH, которая регистрирует любые ошибки ASP.NET, которые происходят в веб-приложении. Я знаю, что вы спрашиваете о решении Winform App, но я чувствовал, что это может быть полезно для всех, кому это нужно, в веб-приложении. Мы используем его там, где я работаю, и это очень полезно при отладке (особенно на рабочих серверах!)
Вот некоторые функции, которые он имеет (вытащил прямо со страницы):
- Регистрация почти всех необработанных исключений.
- Веб-страница для удаленного просмотра всего журнала перекодированных исключений.
- Веб-страница для удаленного просмотра полной информации о любом зарегистрированном исключении.
- Во многих случаях вы можете просмотреть оригинальный желтый экран смерти, который ASP.NET, сгенерированный для заданного исключение, даже в режиме customErrors выключен.
- Уведомление по электронной почте о каждой ошибке в момент ее возникновения.
- RSS-канал последних 15 ошибок из журнала.
- Ряд резервных хранилищ для журнала, включая в памяти, Microsoft SQL Server и некоторые из которых были внесены сообществом.
Ответ 7
Вы можете контролировать большинство исключений в этом обработчике даже в многопоточных приложениях, но .NET(начиная с версии 2.0) не позволит вам отменять необработанные исключения, если вы не включите режим совместимости 1.1. Когда это произойдет, AppDomain будет закрыт, несмотря ни на что. Лучшее, что вы можете сделать, это запустить приложение в другом AppDomain, чтобы вы могли справиться с этим исключением и создать новый AppDomain для перезапуска приложения.
Ответ 8
Я использую следующий подход, который работает и значительно уменьшает количество кода (но я не уверен, есть ли лучший способ или каковы его недостатки.
Всякий раз, когда вы звоните:
Я желаю, чтобы просьбы, дающие минусы, были бы достаточно вежливы, чтобы прояснить их действия; )
try
{
CallTheCodeThatMightThrowException()
}
catch (Exception ex)
{
System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace ();
Utils.ErrorHandler.Trap ( ref objUser, st, ex );
} //eof catch
И вот код ErrorHandler:
Просто сделать clear-: objUser - это объект, моделирующий приложения (вы можете получить информацию, такую как имя домена, отдел, регион и т.д. Для целей ведения журнала
ILog logger - это объект каротажа - например, тот, который выполняет лесозаготовительную деятельность
StackTrace st - объект StackTrace, предоставляющий вам информацию для отладки для вашего приложения.
using System;
using log4net; //or another logging platform
namespace GenApp.Utils
{
public class ErrorHandler
{
public static void Trap ( Bo.User objUser, ILog logger, System.Diagnostics.StackTrace st, Exception ex )
{
if (ex is NullReferenceException)
{
//do stuff for this ex type
} //eof if
if (ex is System.InvalidOperationException)
{
//do stuff for this ex type
} //eof if
if (ex is System.IndexOutOfRangeException)
{
//do stuff for this ex type
} //eof if
if (ex is System.Data.SqlClient.SqlException)
{
//do stuff for this ex type
} //eof if
if (ex is System.FormatException)
{
//do stuff for this ex type
} //eof if
if (ex is Exception)
{
//do stuff for this ex type
} //eof catch
} //eof method
}//eof class
} //eof namesp
Ответ 9
В управляемом графическом приложении по умолчанию исключения, возникающие в потоке графического интерфейса, обрабатываются тем, что назначено в Application.ThreadException.
Исключения, возникающие в других потоках, обрабатываются приложением AppDomain.CurrentDomain.UnhandledException.
Если вы хотите, чтобы ваши исключения потоков GUI работали точно так же, как ваши не-графические интерфейсы, так что они обрабатываются AppDomain.CurrentDomain.UnhandledException, вы можете сделать это:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
Преимущество ловить исключения потоков GUI с помощью ThreadException заключается в том, что вы можете использовать опции, позволяющие приложению продолжить работу. Чтобы убедиться, что никакие файлы конфигурации не переопределяют поведение по умолчанию, вы можете вызвать:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Вы по-прежнему уязвимы для исключений из родных DLL с плохой собственностью. Если native dll устанавливает собственный обработчик с помощью Win32 SetUnhandledExceptionFilter, он должен сохранить указатель на предыдущий фильтр и вызвать его. Если это не так, ваш обработчик не будет вызван.