如何优雅地捕获计时器事件中的异常?

时间:2018-05-23 03:02:19

标签: c# asp.net-core asp.net-core-mvc asp.net-core-2.0

在ASP Net Core 2 MVC应用程序中,我使用this BackGroundService(通过IHostingService)和以下实现来更新实时仪表板的单一规格对象。但是,我不知道确保捕获Update事件被触发时抛出的任何异常的好方法。

注意:我知道AppDomain.UnhandledException,但发现它更像是一个大锤的方法,并希望更容易维护和扩展。

或者,是否有更好的方法来定期更新ASP.NET Core 2中后台任务中的数据?

public class GaugeUpdater : BackgroundService
{
    private readonly List<IUpdateable> _updatables;

    private Timer _timer;

    public GaugeUpdater (IEnumerable<IUpdateable> updateables)
    {
        _updatables = updateables.ToList();
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        if (!stoppingToken.IsCancellationRequested)
        {
            await InitializeUpdateables();

            SetTimer();
        }
    }

    private void SetTimer()
    {
        const int intervalMilliseconds = 60_000;

        var interval = new TimeSpan(0, 0, 0, 0, intervalMilliseconds);
        _timer = new Timer(UpdateAll, null, interval, interval);
    }

    private async Task InitializeUpdateables()
    {
        var tasks = _updatables.Select(x => x.Initialize()).ToList();

        await Task.WhenAll(tasks);
    }

    private async void UpdateAll(object state)
    {
        // TODO: Find way to handle exceptions, as awaiting async void makes it impossible for caller to catch.
        // AppDomain.UnhandledException is possible but hard to maintain and handle in this scope.
        _updatables.ForEach(async x => await x.Update());
    }
}

1 个答案:

答案 0 :(得分:0)

async void可以用于事件处理程序。创建和事件并使用计时器提升它。从那里你应该能够等待异步任务并处理异常

public class GaugeUpdater : BackgroundService {
    private readonly List<IUpdateable> _updatables;
    private Timer _timer;

    public GaugeUpdater (IEnumerable<IUpdateable> updateables) {
        _updatables = updateables.ToList();
        Updating += OnUpdating; //Subscribe to event
    }

    private event EventHandler Updating = delegate { };
    private async void OnUpdating(object sender, EventArgs args) {
        try {
            var tasks = _updatables.Select(x => x.Update());
            await Task.WhenAll(tasks);
        } catch {
            //TODO: Logging???
        }
    }

    private void UpdateAll(object state) {
        Updating(this, EventArgs.Empty); //Raise event
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
        if (!stoppingToken.IsCancellationRequested) {
            await InitializeUpdateables();
            SetTimer();
        }
    }

    private void SetTimer() {
        const int intervalMilliseconds = 60_000;
        var interval = new TimeSpan(0, 0, 0, 0, intervalMilliseconds);
        _timer = new Timer(UpdateAll, null, interval, interval);
    }

    private async Task InitializeUpdateables() {
        var tasks = _updatables.Select(x => x.Initialize()).ToList();
        await Task.WhenAll(tasks);
    }
}