Как получить Исключение, которое происходит в событии Timer Elapsed?

Я работаю с приложением Windows Forms и имею класс менеджера, который использует System.Timers.Timer для периодической проверки данных из базы данных.

Как получить исключение, которое возникает в обработчике событий Elapsed с таймером, доставленное в основное приложение? Если я использую приведенный ниже код, исключение get «проглатывается», и основное приложение никогда не получает его (даже если у меня есть обработчики для ThreadException и UnHandledException).

// Main Form
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

// Manager class
private System.Timers.Timer _timer;

    void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        try
        {
            doSomeDatabaseActions();
        }
        catch (Exception ex)
        {
            throw new ApplicationException("How do I get this error back into main thread...", ex);
        }
    }

Ответы на вопрос(4)

вы можете сгенерировать исключение в другом потоке без таймера:

catch (Exception exception)
{
    ThreadPool.QueueUserWorkItem(
        _ => { throw new Exception("Exception on timer.", exception); });
}
 Jürgen Steinblock20 мар. 2014 г., 14:46
Отлично. Большое спасибо.
 svick21 авг. 2014 г., 16:47
@MonsterMMORPG Да, прямо как в вопросе.
 Mike K31 мар. 2015 г., 18:25
Это сработало для меня в несколько ином контексте, за исключением исключений из рабочих потоков внутри службы Windows. Поскольку потоки запускаются событием Elapsed по таймеру, происходит то же самое.
 Nathan10 окт. 2011 г., 22:14
Ницца. Это сохраняет трассировку стека и перекачивает исключение в AppDomain.UnhandledException. Спасибо!
 anmarti13 сент. 2013 г., 13:36
У меня есть бесконечный цикл с использованием этого подхода. Исключение выбрасывается и обрабатываетсяAppDomain.UnhandledException всегда. Как я могу избежать этого?
 MonsterMMORPG21 авг. 2014 г., 15:03
Это требует обертывания целой функции внутри блока try catch, верно?
 Paul Zaczkowski24 мая 2016 г., 22:53
Фантастически (немного глупо), но это работает. Спасибо!

System.Timers.Timer глотает любое исключение, сгенерированное в обработчике события, вам нужно маршалировать исключение в другой поток (возможно, поток пользовательского интерфейса). Вы можете сделать это черезControl.Invokeили сохраняя информацию об ошибке в переменной-члене и имея поток пользовательского интерфейса, проверяйте эту информацию об ошибке после завершения операции. Если неnullпользовательский интерфейс может затем бросить.

ОтMSDN:

В .NET Framework версии 2.0 и более ранних версиях компонент Timer перехватывает и подавляет все исключения, создаваемые обработчиками событий для события Elapsed. Это поведение может быть изменено в будущих версиях .NET Framework.

Только что проверил в .NET 4.0, и это поведение еще не изменилось.

 hrh25 апр. 2012 г., 18:31
Пример кода Пожалуйста?
 hrh25 апр. 2012 г., 18:41
Я думаю, что понял, я передал исключение в функцию в моем основном потоке, а затем эта функция использовала this.Invoke () для функции перед повторным вызовом исключения. Я правильно понимаю?
 MonsterMMORPG21 авг. 2014 г., 15:02
Есть ли новый метод для обнаружения неожиданных ошибок в .net 4.5? Он все еще сглатывает и не регистрирует ли ошибки в любом случае без упаковки целого _timer_Elapsed внутри try catch?

было ли выброшено исключение:

// Main Form
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

// Manager class
private System.Timers.Timer _timer;

    private exception = null;

    void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        //reset the exception in case object is reused.
        this.exception = null;
        try
        {
            doSomeDatabaseActions();
        }
        catch (Exception ex)
        {
            this.exception = ex;
        }
    }

    /**
    * Checks whether the exception object is set.
    */
    public bool hasExceptionOccured(){
        return (this.exception != null);
    }

    //The main application will call this to get the exception.
    public Exception getException(){
        return this.exception;
    }

что вы хотите обработать исключение в главной форме, это решение не является полным, но показывает, как это сделать с помощью «Действие»

using System;
using System.Timers;


public class MainForm
{
    public MainForm()
    {
        var tm = new TestManager(exception =>
        {
            //do somthing with exception
            //note you are still on the timer event thread
        });

    }
}

public class TestManager
{
    private readonly Action<Exception> _onException;

    public TestManager(System.Action<System.Exception> onException )
    {
        _onException = onException;

    }


    private System.Timers.Timer _timer;
    void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        try
        {
            doSomeDatabaseActions();
        }
        catch (Exception ex)
        {
            //throw new ApplicationException("How do I get this error back into main thread...", ex);
            _onException(ex);
        }
    }

}

Ваш ответ на вопрос