Ответ 1
Если #26
является исключением, вы можете использовать событие AppDomain.CurrentDomain.UnhandledException
. Если это просто возвращаемое значение, то я не вижу никакой возможности справиться с этим глобально.
Я реализовал программное обеспечение, имеющее библиотеку DLL, которая содержит огромный набор классов, который включает в себя все методы для моего программного обеспечения.
Теперь я хочу иметь возможность обрабатывать некоторые глобальные ошибки, такие как ошибка # 26, которая не является связанной с сетью ошибкой для всех этих классов, вместо того, чтобы идти в каждый класс и добавлять ее. Как это сделать?
Если #26
является исключением, вы можете использовать событие AppDomain.CurrentDomain.UnhandledException
. Если это просто возвращаемое значение, то я не вижу никакой возможности справиться с этим глобально.
С его приложением winforms вы можете просто заключить Application.Run(new MainForm());
в блок catch try.
static void Main()
{
try {
Application.Run(new MainForm());
} catch(SystemException)//just as an example
{
//log or handle the error here.
}
}
Я не знаю никаких последствий такого решения, но я просто сказал вам, что вам нужно.
Другие варианты подписываются на Application.ThreadException событие.
Подробнее здесь: unhandledexceptions
Существует также AppDomain.UnhandledException, и вы должны прочитать разницу между ними здесь, на MSDN.
Из MSDN:
Для некоторых моделей приложений событие UnhandledException может быть вытеснено другими событиями, если необработанное исключение встречается в основном потоке приложения.
В приложениях, использующих Windows Forms, необработанные исключения в основном потоке приложения вызывают событие Application.ThreadException. Если это событие обрабатывается, поведение по умолчанию заключается в том, что необработанное исключение не завершает приложение, хотя приложение остается в неизвестном состоянии. В этом случае событие UnhandledException не создается. Это поведение можно изменить с помощью файла конфигурации приложения или с помощью метода Application.SetUnhandledExceptionMode, чтобы изменить режим на UnhandledExceptionMode.ThrowException до того, как обработчик события ThreadException подключен. Это относится только к основной теме приложения. Событие UnhandledException создается для необработанных исключений, созданных в других потоках.
С ссылкой Централизованная обработка исключений в приложении С# Windows я нашел одно из хороших решений:
static class Program
{
[STAThread]
static void Main()
{
// Add handler to handle the exception raised by main threads
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
// Add handler to handle the exception raised by additional threads
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
// Stop the application and all the threads in suspended state.
Environment.Exit(-1);
}
static void Application_ThreadException
(object sender, System.Threading.ThreadExceptionEventArgs e)
{// All exceptions thrown by the main thread are handled over this method
ShowExceptionDetails(e.Exception);
}
static void CurrentDomain_UnhandledException
(object sender, UnhandledExceptionEventArgs e)
{// All exceptions thrown by additional threads are handled in this method
ShowExceptionDetails(e.ExceptionObject as Exception);
// Suspend the current thread for now to stop the exception from throwing.
Thread.CurrentThread.Suspend();
}
static void ShowExceptionDetails(Exception Ex)
{
// Do logging of exception details
MessageBox.Show(Ex.Message, Ex.TargetSite.ToString(),
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
В вышеприведенном классе мы присоединим обработчик событий к двум событиям. Лучше присоединить эти события, как только начнется основной метод.
Application.ThreadException. Это событие будет поднято, если исключение будет передано в основном потоке. Если мы добавим обработчик событий, то исключение обрабатывается по методу.
AppDomain.CurrentDomain.UnhandledException. Это событие будет поднято, когда исключение будет добавлено в дополнительные потоки, используемые в приложении. Хуже сценарий здесь, как только выполнение обработчиков заканчивается, исключение снова бросается, тогда как приложение заканчивается. Это необходимо обработать. Здесь я использовал немного кода для обработки этой ситуации и продолжения выполнения приложения без перерыва.
Логика, которую я использовал для преодоления этой ситуации, - это просто приостановить поток в обработчике событий, чтобы приложение продолжало работать нормально. Снова возникает проблема приостановки этого потока. Когда основная форма закрыта, приложение обычно должно выйти, но по мере того, как поток находится в состоянии приостановления, приложение все равно будет работать. Таким образом, чтобы полностью завершить приложение и остановить процесс, необходимо вызывать Environment.Exit(-1) до окончания основного метода.
Во-первых, вы должны добавить:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
После этого вы можете перехватывать исключения, например:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += ApplicationThreadException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
if (DataBaseMNG.Init())
{
Application.Run(new MainForm());
}
}
/// <summary>
/// Global exceptions in Non User Interfarce(other thread) antipicated error
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var message =
String.Format(
"Sorry, something went wrong.\r\n" + "{0}\r\n" + "{1}\r\n" + "please contact support.",
((Exception)e.ExceptionObject).Message, ((Exception)e.ExceptionObject).StackTrace);
MessageBox.Show(message, @"Unexpected error");
}
/// <summary>
/// Global exceptions in User Interfarce antipicated error
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ApplicationThreadException(object sender, ThreadExceptionEventArgs e)
{
var message =
String.Format(
"Sorry, something went wrong.\r\n" + "{0}\r\n" + "{1}\r\n" + "please contact support.",
e.Exception.Message, e.Exception.StackTrace);
MessageBox.Show(message, @"Unexpected error");
}
Обработайте событие Application.ThreadException.
Глобальный перехват ошибок в winforms
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try
{
Application.Run(new myForm());
}
catch (Exception ex)
{
HandleException(ex);
}
}
internal static void HandleException(Exception ex)
{
string LF = Environment.NewLine + Environment.NewLine;
string title = $"Oups... I got a crash at {DateTime.Now}";
string infos = $"Please take a screenshot of this message\n\r\n\r" +
$"Message : {LF}{ex.Message}{LF}" +
$"Source : {LF}{ex.Source}{LF}" +
$"Stack : {LF}{ex.StackTrace}{LF}" +
$"InnerException : {ex.InnerException}";
MessageBox.Show(infos, title, MessageBoxButtons.OK, MessageBoxIcon.Error); // Do logging of exception details
}
}
Как продолжение того, что показано выше, я использую следующее:
try
{
Application.Run(new FormMain());
}
catch (Exception ex)
{
RoboReporterConstsAndUtils.HandleException(ex);
}
... где метод HandleException() может быть примерно таким:
internal static void HandleException(Exception ex)
{
var exDetail = String.Format(ExceptionFormatString,
ex.Message,
Environment.NewLine,
ex.Source,
ex.StackTrace,
ex.InnerException);
ExceptionLoggingService.Instance.LogAndEmailExceptionData(string.Format("{0}: {1}: {2}",
DateTime.Now.ToLongDateString(), GetVersionInfo(), exDetail));
}
Другой способ обмануть этого кота:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AppDomain.CurrentDomain.UnhandledException += Unhandled;
Application.Run(new FormMain());
}
static void Unhandled(object sender, UnhandledExceptionEventArgs exArgs)
{
ExceptionLoggingService.Instance.LogAndEmailMessage(String.Format
("From application-wide exception handler: {0}", exArgs.ExceptionObject));
}
Конечно, вы можете делать все, что захотите, в методе Unhandled().