AsyncContext - > AsyncContextThread处理异常

时间:2017-09-29 14:42:11

标签: c# async-await windows-services

关于:AsyncContextThread

https://github.com/StephenCleary/AsyncEx/wiki/AsyncContext

https://github.com/StephenCleary/AsyncEx/blob/master/src/Nito.AsyncEx.Context/AsyncContextThread.cs

没有真正介绍如何处理线程启动时发生的捕获异常。

public partial class MyService : ServiceBase
{
    private readonly AsyncContextThread _thread = new AsyncContextThread();

    private readonly CancellationTokenSource _cts = new CancellationTokenSource();

    public MyService()
    {
        InitializeComponent();
    }

    public void Start()
    {
        OnStart(null);
    }    

    protected override void OnStart(string[] args)
    {
        try
        {     
            _thread.Factory.Run(StartAsync);
        }
        catch (Exception ex)
        {                
            // Exception?
        }
    }

    private async Task StartAsync()
    {
        throw new Exception("things went wrong");
    }

    protected override void OnStop()
    {
        if (!_cts.IsCancellationRequested)
            _cts.Cancel();
        _thread.JoinAsync().GetAwaiter().GetResult();
    }
}

我似乎没有抓住catch{}块中的任何内容,此外我尝试将这些添加到我的Program.cs(主入口点)。

TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

但是,上述代码中都没有触发任何事件处理程序方法。

问)在这种情况下如何正确处理异常?

作为旁注,我很确定先前使用AsyncContext并在Visual Studio中调试确实捕获了异常,因此我不确定是否存在某些同步。在尝试为异常添加处理程序时,我缺少上下文。

修改

我知道我可以在try/catch方法中StartAsync,但我得到的一点是能够捕获任何未处理的异常,并确保我可以记录它们。

2 个答案:

答案 0 :(得分:3)

您可以使用Continuation来处理例外情况。

protected override void OnStart(string[] args)
{
    _thread.Factory.Run(StartAsync).ContinueWith(t =>
    {
        var aggregate = t.Exception.Flatten();
        foreach(var exception in aggregate.InnerExceptions)
        {
            // Handle exception
        }
    }, TaskContinuationOptions.OnlyOnFaulted);
}

答案 1 :(得分:2)

我一直想写一篇关于异步Win32服务的博客文章......几年了......:)

  

没有真正介绍如何处理线程启动时发生的捕获异常。

AsyncContextThread实际上是在创建后立即启动的。您在OnStart上正在做的是将工作排到其上下文中。

Task返回的Run上观察到该工作的例外情况,观察它的适当方法是使用await

protected override async void OnStart(string[] args)
{
    try
    {     
        await _thread.Factory.Run(StartAsync);
    }
    catch (Exception ex)
    {                
        // Exception!
    }
}

一些注意事项:

通常情况下,您应该avoid async void。该规则的例外是事件处理程序或类似事件的方法(例如OnStart)。当您 使用async void时,您应该考虑在整个try方法主体(我们这样做)周围catch / async void。< / p>

await is superior to ContinueWith。在这种特殊情况下,ContinueWith可以正常工作,但在一般情况下,这是不可取的:它不理解async个委托,它不使用适当的默认TaskScheduler,它确实不使用适当的默认延续标志。这些都是await为您处理的所有事情。