Подтвердить что ты не робот

Как получить исключение, которое происходит в событии "Истекшее время таймера"?

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

Как получить Исключение, которое происходит в таймере Истекший обработчик событий, отправленный в основное приложение? Если я использую приведенный ниже код, исключение получает "проглотил", и основное приложение никогда не получает его (даже если у меня есть обработчики для 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);
        }
    }
4b9b3361

Ответ 1

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

catch (Exception exception)
{
    ThreadPool.QueueUserWorkItem(
        _ => { throw new Exception("Exception on timer.", exception); });
}

Ответ 2

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

От MSDN:

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

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

Ответ 3

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

// 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;
    }

Ответ 4

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

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);
        }
    }

}