Mandar Jogalekar
Mandar Jogalekar

Reputation: 3281

Async Task not returning to main thread

I think this has something to do with my really bad async programming.

Here it goes. I am fetching mailchimp subscribers using an async method but the result just hangs and never returns to main thread.

The async method

public async Task<List<Subscriber>> GetMailChimpSubscribers()
{
    TaskCompletionSource<List<Subscriber>> result = new TaskCompletionSource<List<Subscriber>>();
    await Task.Run(async () =>
    {
        var subscribers = new List<Subscriber>();
        var listId = "";
        var members = await _manager.Members.GetAllAsync(listId);
        foreach (var item in members)
        {
            var sub = new Subscriber();
            sub.Email = item.EmailAddress;
            subscribers.Add(sub);
        }
        result.SetResult(subscribers);
    });
    return result.Task.Result;
}

This hangs after result.SetResult(subscribers) statement completely.

This is called from

public static List<Subscriber> GetSubscribers()
{
    MailchimpHelper helper = new MailchimpHelper();
    var subscribers= helper.GetMailChimpSubscribers();

    return subscribers.Result;
}

What exactly is wrong here? Is the setup wrong?

PS : there isn't an issue with mailchimp or the api , it works great in console. this is purely something bad with async programming

UPDATE:

In case this is faced by someone. the blog helped to clear a lot

https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

the working solution from below answers and blog.

public async Task<List<Subscriber>> GetMailChimpSubscribers()
   {
    var subscribers = new List<Subscriber>();
    var listId = "";
    var members = 
     await   _manager.Members.GetAllAsync(listId).**ConfigureAwait(false)**;

    foreach (var item in members)
    {
        var sub = new Subscriber();
        sub.Email = item.EmailAddress;
        subscribers.Add(sub);
    }

    return subscribers;


} 

public static List<Subscriber> GetSubscribers()
{
    MailchimpHelper helper = new MailchimpHelper();
    var subscribers= helper.GetMailChimpSubscribers();
    subscribers.Wait();

    return subscribers.Result;
}

Upvotes: 0

Views: 1463

Answers (3)

Camilo Terevinto
Camilo Terevinto

Reputation: 32068

The first part of the problem is that you are, for some weird reason, wrapping the task inside another task. Change your method to this:

public async Task<List<Subscriber>> GetMailChimpSubscribers()
{
    var subscribers = new List<Subscriber>();
    var listId = "";
    var members = await _manager.Members.GetAllAsync(listId);
    foreach (var item in members) //this foreach could be a simpler LinQ statement
    {
        var sub = new Subscriber();
        sub.Email = item.EmailAddress;
        subscribers.Add(sub);
    }

    return subscribers;
}

You should also be calling this method using await, but if this is not possible then change your method to this:

public static List<Subscriber> GetSubscribers()
{
    MailchimpHelper helper = new MailchimpHelper();
    var subscribers = helper.GetMailChimpSubscribers();
    subscribers.Wait();
    return subscribers.Result;
}

Upvotes: -1

Don't use .Result in environments with a synchronization context - it creates a circular wait.

In general, try to use async "all the way down" if possible - i.e. if you're going to use async/await at all, you should only use async/await.

Please see Don't Block on Async Code by Stephen Cleary for more details.

Upvotes: 1

Stephen Cleary
Stephen Cleary

Reputation: 456437

There's a lot wrong here:

Removing all the bad parts leaves us with:

public async Task<List<Subscriber>> GetMailChimpSubscribersAsync()
{
  var subscribers = new List<Subscriber>();
  var listId = "";
  var members = await _manager.Members.GetAllAsync(listId);
  foreach (var item in members)
  {
    var sub = new Subscriber();
    sub.Email = item.EmailAddress;
    subscribers.Add(sub);
  }
  return subscribers;
}

public static async Task<List<Subscriber>> GetSubscribersAsync()
{
  MailchimpHelper helper = new MailchimpHelper();
  return await helper.GetMailChimpSubscribersAsync();
}

Upvotes: 8

Related Questions