3

I'm trying to download some twitter info asynchronously and it's blocking the UI thread. I'm using LinqToTwitter (http://linqtotwitter.codeplex.com/) to download the info.

Here's the call to the task

PublicTweetListBox.ItemsSource = await getTweets(twitterCtx);

And here's the task itself

async Task<List<TweetViewModel>> getTweets(TwitterContext twitterCtx)
{       
    var tweetList = await Task.FromResult<List<TweetViewModel>>(
    (from tweet in twitterCtx.Status
    where tweet.Type == StatusType.User
    && tweet.ScreenName == UserName.Text
    select new TweetViewModel
    {
        Name = tweet.User.Name,
        Tweet = tweet.Text,
        ImageUrl = tweet.User.ProfileImageUrl
    })
    .ToList());

    return tweetList;

}

I'm doing something wrong in the way I await downloading the list, TweetViewModel is a custom type if that helps.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Nick Ward
  • 33
  • 4

3 Answers3

5

async and await do not magically make blocking code non-blocking. Linq-to-twitter is not an asynchronous API, and sticking it in a Task.FromResult will do nothing.

If you want to push the querying to a background thread, you could use Task.Run instead of Task.FromResult. A more efficient (but more involved) solution would be to use an asynchronous twitter API.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
1

Previous answers were good and I just want to add to what has been said. LINQ doesn't support C# 5.0 async, so here's what I did with LINQ to Twitter to support it:

    static void AsyncSearchSample(TwitterContext twitterCtx)
    {
        (from search in twitterCtx.Search
         where search.Type == SearchType.Search &&
               search.Query == "LINQ To Twitter"
         select search)
        .MaterializedAsyncCallback(resp =>
        {
            if (resp.Status != TwitterErrorStatus.Success)
            {
                Exception ex = resp.Error;
                // handle error
                throw ex;
            }

            Search srch = resp.State.First();
            Console.WriteLine("\nQuery: {0}\n", srch.SearchMetaData.Query);

            srch.Statuses.ForEach(entry =>
                Console.WriteLine(
                    "ID: {0, -15}, Source: {1}\nContent: {2}\n",
                    entry.ID, entry.Source, entry.Text));
        });
    }

The MaterializedAsyncCallback takes a parameter of type TwitterAsyncResult<IEnumerable<T>>, resp, where T is the entity type. In this example T is Search. The resp.Status lets you know if an exception was raised during the call and gives you access through the resp.Error property. The resp.State gives you access to the IEnumerable<T>, which is a single Search entity that contains metadata and a list of Status entities (tweets).

The underlying HTTP calls do execute asynchronously, though they use APM, rather than C# 5.0 async. I have plans to look at async closer for both queries and commands in the future, but what LINQ to Twitter uses today is quite effective.

@JoeMayo

Joe Mayo
  • 7,501
  • 7
  • 41
  • 60
  • Thanks a lot Joe! I'm loving linqtotwitter so far, I look forward to async support, keep up the good work – Nick Ward Dec 03 '12 at 17:41
-1

It's blocking the UI thread because that is what await is meant to do. :)

The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work.

http://msdn.microsoft.com/en-us/library/hh156528.aspx

IMO this is a "hack" to async programming to work in a synchronous way. To load items in the background and update the ItemSource when complete, use a worker thread and a call to 'Dispatcher.Invoke' to update the ItemSource with the results.

Steve Py
  • 26,149
  • 3
  • 25
  • 43
  • 1
    When `await` is given an operation that has not yet completed, it suspends the execution of the method and does *not* block the thread. – Stephen Cleary Nov 28 '12 at 05:14