使用带有异步任务和等待的ConfigureAwait(false)是否会传播异常?

问题描述 投票:0回答:1

我感觉我已经很好地掌握了异步等待编程,但今天发生的事情让我感到困惑。我一直在寻找这个问题的答案有一段时间了,但无法在任何地方找到它。我已经阅读了大量有关异步等待编程的内容,但我脆弱的头脑无法理解在这个特定场景中到底发生了什么。

我有这两种方法:

public async Task<IEnumerable<ServerStatus>> GetServersStatusAsync()
{
    var serverStatuses = new List<ServerStatus>();
    try
    {
        ServerStatusRequest request = new ServerStatusRequest();
        var serverStatusResponse = await GetAsync<ServerStatusResponse>(request).ConfigureAwait(false);
    }
    // I would expect the exception thrown from GetAsync to be caught here. But it doesn't always do that.
    catch (Exception ex)
    {
        _log.Error("Failed to retrieve server statuses.", ex);
    }
    return serverStatuses;
}

还有

private async Task<T> GetAsync<T>(IRequest request)
{
    string respString = string.Empty;
    try
    {
        
        var requestUrl = request.GetQueryString(_apiToken);
        _log.Debug($"Sending a request to {requestUrl}");
        CancellationTokenSource tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(_timeoutInSec));

        //This call can throw an exception. It will always get caught inside this current try catch, 
        //but if after the await we are continuing on a different thread, 
        //the re-thrown/propagated exception is not caught by the calling method.
        var response = await _client.GetAsync(requestUrl, tokenSource.Token).ConfigureAwait(false);

        if (response.IsSuccessStatusCode || response.StatusCode == HttpStatusCode.BadRequest)
        {
            respString = await response.Content.ReadAsStringAsync();
            var deserializedObject = JsonConvert.DeserializeObject<T>(respString);
            return deserializedObject;
        }
    }
    catch (Exception ex) when (ex is JsonReaderException || ex is JsonSerializationException)
    {
        throw new JsonSerializationException($"Failed to deserialize {respString}", ex) { Source = respString };
    }

    return default(T);
}

我在代码片段中添加了 2 条注释作为指针,但基本思想是:

在 GetServerStatusAsync 中,我用 try catch 包装了所有内容,因为我想处理那里的异常。我调用 GetAsync,它等待使用ConfigureAwait(false) 调用 HttpClient.GetAsync。当 HttpClient.GetAsync 的调用返回时出现异常(如果我们不再位于初始线程/上下文中),则可以在我的 GetAsync 方法中捕获该异常,但不会传播到 GetServerStatusAsync。如果我删除ConfigureAwait(false),它总是按照我的预期向下传播,但是使用ConfigureAwait(false),它更像是50/50。

我的代码或我对异步等待的理解是否存在灾难性的错误?

非常感谢任何帮助。

编辑: 根据评论中的请求,我添加了调用 GetServersStatusAsync 的方法的简化版本以及如何调用该方法(以一劳永逸的方式,但登录是用 try catch 包装的,因此这不应该是一个大问题).

public async Task Login(Action<LoginResult> callback = null)
{

    LoginResult result = new LoginResult() { Success = false };
    try
    {
            var serverStatus = await GetServersStatusAsync();
            if (serverStatus.Any())
            {
                result.Success = true;
                callback?.Invoke(result);
                return;
            }
    }
    catch (Exception ex)
    {
        result.Message = Strings.UnknownException;
        _log.Error("Login failed due to unexpected exception", ex);
    }
    callback?.Invoke(result);
}
 _restClient.Login(OnLoginResponse);
c# asynchronous async-await configureawait
1个回答
0
投票

Azure.Messaging.ServiceBus.ServiceBusSender 7.10.0.0

似乎也使用 .ConfigureAwait(false);

所以如果你做类似的事情...

 await serviceBusSender.PublishAsync(serviceBusMessage, cancellationToken);
 await recordWeSentIt(serviceBusMessage);

我的想法是否正确,这可能意味着如果有什么事情中断了网络,我们可以将消息记录为已发送,这样发布就永远不会发生?

© www.soinside.com 2019 - 2024. All rights reserved.