Exception not caught - AggregateException not handled

Does anyone know why the following code won't catch my ConnectionException, I am spending hours with it ...

    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;
    }

      

When SearchContactsAsync throws an exception, the exception is not caught by the LoadContacts method and is propagated as an unhandled AggregateException. I wrote some unit tests and they all pass, the problem occurs in the application launch. I appreciate any help.

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 impl:

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}");
    }

      

ProvideAsync using TPL and TCS queue:

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;
    }

      

And finally, the queue consumer that throws an exception using the TaskCompletionSource object:

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;
            }
        }
    }

      

0


source to share


3 answers


Ok, I see the problem right now. The last line of code I posted ... it throws an exception again that never gets caught ... What a mistake. Anyway, thanks to everyone involved for their help ...



-1


source


Tasks for SearchContactsAsync here

for (int i = 0; i < addressBookServers.Count; i++)
     tasksToProcess.Add(_addressBookService.SearchContactsAsync(addressBookServers[i].Id, filterUpCaseNoDiacritics));

      

These tasks are waiting outside the try block:

var processedTask = await Task.WhenAny(tasksToProcess);
tasksToProcess.Remove(processedTask);
try
{
    // Rest of your code

      



Therefore, if one of these tasks throws an exception, nothing handles it. Move the lines

var processedTask = await Task.WhenAny(tasksToProcess);
tasksToProcess.Remove(processedTask);

      

inside a try block.

+1


source


You are not catching an aggregate exception , which is why your exception is not being handled.

//Following code is just an outline and you need to correct according to your requirement.

          try {
                 //your task
              }
          catch (AggregateException ae)
          {
             ae.Handle( x => 
                       { 
                            // Handle an ErrorMessageException
                            if (x is ErrorMessageException) {
                                //do your logging
                                return true; //if you handled it through logging or reporting
                            }
                            // Handle an ConnectionException
                            else if(x is ConnectionException){ 
                              //do your logging for connection
                              return true;  //if you handled it through logging or reporting 
                             }
                           else
                               return false; //This leave the exception as unhandled aggregate exception.

                       });
          }

      

0


source







All Articles