【发布时间】:2016-12-09 00:25:51
【问题描述】:
有谁知道为什么下面的代码没有捕捉到我的 ConnectionException,我已经花了几个小时...
public async Task LoadContacts(string filter)
{
// We will send find contacts message to all servers supporting addressbook.
var addressBookServers = _addressBookService.GetAddressBookServerList();
// Create task array here to be able to run each task in parallel manner.
var tasksToProcess = new List<Task<SearchContactsResultDto>>(addressBookServers.Count);
for (int i = 0; i < addressBookServers.Count; i++)
tasksToProcess.Add(_addressBookService.SearchContactsAsync(addressBookServers[i].Id, filterUpCaseNoDiacritics));
while (tasksToProcess.Count > 0)
{
var processedTask = await Task.WhenAny(tasksToProcess);
tasksToProcess.Remove(processedTask);
try
{
var serverResponse = await processedTask.ConfigureAwait(false);
var vmToAdd = serverResponse.SearchedContacts
.Where(sc => !SearchedContacts.Exists(c => c.BabelName == sc.BabelName))
.Select(sc => CreateSearchContactViewModel(serverResponse.ServerId, null, sc.Name, sc.BabelName, sc.ContactId));
SearchedContacts.AddRange(vmToAdd);
}
catch (ErrorMessageException eme) { Log.Warning(s => s.Set($"An {nameof(ErrorMessageException)} of type {eme.ErrorMessage.Cause} threw as a response to {nameof(Core.Json.Messages.MsgFindContacts)}. See exception details for further information.", eme)); }
catch (ConnectionException ce) { Log.Info(s => s.Set($"Connection with server cannot be reached. Message of type {nameof(Core.Json.Messages.MsgFindContacts)} cannot be send", ce)); }
catch (TimeoutException te) { Log.Info(s => s.Set($"Request on a message of type {nameof(Core.Json.Messages.MsgFindContacts)} timeouted. See exception details for further details.", te)); }
catch (Exception) {}
}
IsLoadingContacts = false;
}
当 SearchContactsAsync 抛出异常时,该异常不会被 LoadContacts 方法捕获,而是作为未处理的 AggregateException 传播。 我写了一些单元测试,它们都通过了,问题出现在运行应用程序中。 感谢您的帮助。
SearchContactsAsync 实现:
public async Task<SearchContactsResultDto> SearchContactsAsync(int serverId, string filter)
{
var msgFindContactsRes = await _communicationService.SendFindContactsAsync(serverId, filter)
.ConfigureAwait(false);
return new SearchContactsResultDto()
{
ServerId = serverId,
SearchedContacts = msgFindContactsRes.Contacts,
PageNumber = msgFindContactsRes.PageNumber,
PageSize = msgFindContactsRes.PageSize
};
}
SendFindContacsAsync 实现:
public Task<MsgFindContactsRes> SendFindContactsAsync(int serverId, string filter)
{
var serverSender = serverConnectionProvider.ProvideSender(serverId);
var msgFindContacts = messageFactory.CreateMsgFindContacts(filter);
return serverSender.SendAsync<MsgFindContactsRes>(msgFindContacts);
}
SendAsync:
public async Task<TExpectedResponse> SendAsync<TExpectedResponse>(IMessage message)
where TExpectedResponse : class, IMessage
{
if (message == null)
throw new ArgumentNullException($"Argument {nameof(message)} cannot be null.");
var response = await _queue.ProvideAsync(message).ConfigureAwait(false);
if (response is TExpectedResponse)
return response as TExpectedResponse;
else throw new InvalidServerResponseException($"Invalid response to a message of type {message.Header.Type}, expected message type: {typeof(TExpectedResponse).FullName}, received message type: {response.Header.Type}. Server id: {_serverConnection.ServerId}");
}
使用 TPL 队列和 TCS 提供异步:
public Task<TItemResult> ProvideAsync(TItemData item)
{
TaskCompletionSource<TItemResult> tcs = new TaskCompletionSource<TItemResult>();
// async enqueue an item with its task completion source
_queue.SendAsync<QueueItem<TItemData, TItemResult>>(new QueueItem<TItemData, TItemResult>(tcs, item));
return tcs.Task;
}
最后是使用 TaskCompletionSource 引发异常的队列消费者:
private async Task StartConsumer(Func<TItemData, TItemResult> consumer)
{
while (await _queue.OutputAvailableAsync())
{
QueueItem<TItemData, TItemResult> res = await _queue.ReceiveAsync();
try
{
var result = consumer(res.Data);
res.Tcs?.SetResult(result);
}
catch (Exception e)
{
res?.Tcs.SetException(e);
throw;
}
}
}
【问题讨论】:
-
捕获
AggregateException并将其解包(循环通过InnerExceptions属性。然后它会告诉您代码的确切问题,并让您了解代码的哪一部分实际上失败了。 -
尝试从您的方法中删除
ConfigureAwait(false)。这只是一个猜测,而我正在尝试使用像您一样的真实服务来重现这一点。 -
您是否在所有三个“捕获”中都设置了断点,以查看它是否真的到达那里?我认为您的三个“捕获”(ErrorMessageException、ConnectionException 或 TimeoutException,但不是通用的异常捕获块)之一可能会捕获异常,并且
Log.Info()或Log.Warning()方法本身会抛出异常,没有被捕获,因为在您现有的 try catch 之外没有另一个 try catch 块。 -
@Alisson,好点,我试图在其中添加断点,你是对的.. 异常被捕获,无论如何它仍然传播给调用者。我看不出发生这种情况的原因以及如何立即解决它。我试图删除日志调用,但没有任何改变......
-
@Alisson,删除 ConfigureAwait 没有帮助...
标签: c# exception-handling async-await