2017-09-29 17 views
2

关于:AsyncContextThreadAsyncContext - > 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; 

但是在上面的代码中没有触发事件处理程序方法。

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

作为一个方面说明,我相当确定以前使用AsyncContext并在Visual Studio中进行调试确实发现了异常,所以我不确定是否有某种同步。上下文我很想念,当试图添加异常处理程序。

编辑

我知道我可以在StartAsync方法中try/catch,但我在获得关键是能够捕捉任何未处理的异常,并确保我可以登录他们。

+0

我拼命希望斯蒂芬Cleary回答这个问题:) – peteski

+1

我认为你需要'等待''try'中的方法来捕获异常。目前异步方法将立即返回给调用者,抛出的错误将丢失。 – Equalsk

+0

@Equalsk你不能在Windows服务的OnStart方法中“等待”任何东西,因为它是一个覆盖,并且必须匹配预期的签名。 AsyncContext/AsyncContextThread的整个想法(据我所知)是允许你从不允许的地方启动异步方法(即控制台应用程序或Windows服务)。 – peteski

回答

2

我一直做异步的Win32服务......现在几年一篇博客文章... :)

它真不是盖的如何处理捕获例外线程启动时发生。

AsyncContextThread实际上在创建后立即启动。你在做什么OnStart是排队工作的上下文。

对这项工作的例外是在从Run返回Task观察,并观察它适当的方法是使用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方法体(我们这样做)。

await is superior to ContinueWith。在这种特殊情况下,ContinueWith可以正常工作,但在一般情况下,这是不可取的:它不理解async代表,它不使用适当的默认TaskScheduler,它不使用适当的默认延续标志。这些都是await只是为你处理。

+0

感谢Stephen的回复,只是跟进,我有'public void Start()'方法在Visual Studio中调试时运行,我应该试着获取awaiter和它的结果,或者只是把它作为service.Start();? – peteski

+1

我想你必须使用'Start()'。由于它不返回任务,因此无法阻止它。 –

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

我明白什么你在说,我认为我希望得到Stephen关于这个问题的意见的原因是他的书“C#Cookbook中的并发”(第35/36页)讨论了在异步void类型方法中处理异常。给出的代码示例并没有使用延续,而是使用了代码示例中的try/catch,因此这看起来不正确。 – peteski