Reputation: 3281
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
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
Reputation: 12181
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
Reputation: 456437
There's a lot wrong here:
TaskCompletionSource<T>
.Task.Run
is unnecessary.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