You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Async异常未捕获:Windows Service中try..catch无法捕获RefreshTokenException

问题分析与解决方案

你遇到的核心问题是**async void方法的异常无法被调用方的try/catch捕获**,这是异步编程里很容易踩的一个坑,我来给你拆解清楚:

为什么捕获不到异常?

在.NET的异步编程模型里,async void和async Task/async Task<T>的异常处理逻辑完全不同:

  • 用async Task时,方法抛出的异常会被包装在返回的Task对象中,调用方通过await就能正常捕获这些异常;
  • 但async void是专门为传统事件处理场景设计的,它抛出的异常不会回传到调用方,而是直接抛到当前线程的同步上下文(SynchronizationContext)里。在Windows Service这种没有UI同步上下文的环境中,这些异常会直接终止进程,根本不会进入你写的try/catch块。

看你的代码就能发现问题:

  • RefreshTokens是async void方法,里面抛出的RefreshTokenException不会被调用方Process的try/catch捕获;
  • 更糟的是Process本身也是async void,它自己的异常也无法被上层代码捕获。

修复步骤

1. 把所有async void改成async Task

首先修改RefreshTokens的方法签名:

private async Task RefreshTokens() 
{ 
    try 
    { 
        var cognito = new CognitoApi(); 
        var response = cognito.TokenRefresh(_refreshToken); 
        if (response.HttpStatusCode == HttpStatusCode.OK) 
        { 
            _idToken = new AwsToken(response.AuthenticationResult.IdToken); 
            _accessToken = new AwsToken(response.AuthenticationResult.AccessToken); 
        } 
        else 
        { 
            await _signIn(_credentials.SiteId, _credentials.LocationId, null); 
        } 
    } 
    catch (NotAuthorizedException) 
    { 
        await _signIn(_credentials.SiteId, _credentials.LocationId, null); 
    } 
    catch (Exception ex) 
    { 
        throw new RefreshTokenException("Failed refreshing tokens.", ex); 
    }
}

然后修改Process的签名,并且必须用await调用RefreshTokens:

public async Task Process(QueueMessage queueMessage, Action<QueueMessage> retryAction) 
{ 
    _processingCounter.Increment(); 
    try 
    { 
        // ...... 
        IAwsToken idToken = authenticationService.Tokens.IdToken; 
        // 这里一定要加await,才能捕获到RefreshTokens里的异常
        await RefreshTokens();
        // ........ 
    } 
    catch (Exception ex) 
    { 
        // 现在就能正常捕获到RefreshTokenException了
        _logger.Error("Error in ProcessMessage", ex); 
    } 
    _processingCounter.Decrement();
}

2. 在Windows Service中正确调用异步方法

如果Process是被Windows Service的启动逻辑或定时任务调用,要注意调用方的异步处理:
比如在OnStart这种同步方法里,不能直接await,可以用Task.Run包裹,同时要捕获内部异常避免进程崩溃:

protected override void OnStart(string[] args)
{
    _ = Task.Run(async () =>
    {
        try
        {
            await Process(queueMessage, retryAction);
        }
        catch (Exception ex)
        {
            _logger.Error("Unhandled exception in service", ex);
        }
    });
}

关键总结

  • 非事件处理场景下,永远不要用async void,用async Task代替;
  • 所有异步方法调用必须加await,这样异常才能被上层的try/catch捕获;
  • Windows Service这类无UI环境中,一定要格外注意异步方法的异常处理,避免未捕获异常导致进程意外终止。

内容的提问来源于stack exchange,提问作者Andrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:37:45