我感觉我已经很好地掌握了异步等待编程,但今天发生的事情让我感到困惑。我一直在寻找这个问题的答案有一段时间了,但无法在任何地方找到它。我已经阅读了大量有关异步等待编程的内容,但我脆弱的头脑无法理解在这个特定场景中到底发生了什么。
我有这两种方法:
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);
Azure.Messaging.ServiceBus.ServiceBusSender 7.10.0.0
似乎也使用 .ConfigureAwait(false);
所以如果你做类似的事情...
await serviceBusSender.PublishAsync(serviceBusMessage, cancellationToken);
await recordWeSentIt(serviceBusMessage);
我的想法是否正确,这可能意味着如果有什么事情中断了网络,我们可以将消息记录为已发送,这样发布就永远不会发生?