3

Been stuck for days, hoping someone can help me.

I have been trying to run the YouTube 'Search by keyword' example from Google's API examples for .net in a VS 2013 Express for Web MVC4 project, and the ExecuteAsync() calling the Google API never comes back.

I believe the example code works as I tested it in VS 2013 Express for Windows Desktop as a console application and it came back fine. Also the stats in google's developers console tell me the API request is being received.

Here is what I did:

I created a new VS 2013 Express for Web MVC4 project called GoogleTest and installed the 'Install-Package Google.Apis.YouTube.v3' package.

I then added the following model.

public class SearchYouTube
{
    public int ID { get; set; }

    public async Task RunYouTube()
    {
        var youtubeService = new YouTubeService(new BaseClientService.Initializer()
        {
            ApiKey = " <MY DEVELOPER KEY HERE> ",
            ApplicationName = this.GetType().ToString()
        });

        var searchListRequest = youtubeService.Search.List("snippet");
        searchListRequest.Q = "googleapi examples"; // Replace with your search term.
        searchListRequest.MaxResults = 50;

        // Call the search.list method to retrieve results matching the specified query term.
        var searchListResponse = await searchListRequest.ExecuteAsync();

        List<string> videos = new List<string>();
        List<string> channels = new List<string>();
        List<string> playlists = new List<string>();

        // Add each result to the appropriate list, and then display the lists of
        // matching videos, channels, and playlists.
        foreach (var searchResult in searchListResponse.Items)
        {
            switch (searchResult.Id.Kind)
            {
                case "youtube#video":
                    videos.Add(String.Format("{0} ({1})", searchResult.Snippet.Title, searchResult.Id.VideoId));
                    break;

                case "youtube#channel":
                    channels.Add(String.Format("{0} ({1})", searchResult.Snippet.Title, searchResult.Id.ChannelId));
                    break;

                case "youtube#playlist":
                    playlists.Add(String.Format("{0} ({1})", searchResult.Snippet.Title, searchResult.Id.PlaylistId));
                    break;
            }
        }

        Console.WriteLine(String.Format("Videos:\n{0}\n", string.Join("\n", videos)));
        Console.WriteLine(String.Format("Channels:\n{0}\n", string.Join("\n", channels)));
        Console.WriteLine(String.Format("Playlists:\n{0}\n", string.Join("\n", playlists)));
    }
}

Then I call the above class in the Home controller like so:

public ActionResult Index()
{
    ViewBag.Message = "MVC example";

    SearchYouTube searchObject = new SearchYouTube();
    searchObject.RunYouTube().Wait();

    return View();
}

Running this in the debugger, the program steps into but never returns from this line in the SearchYouTube class above:

var searchListResponse = await searchListRequest.ExecuteAsync();

Can anyone help explain what I am doing wrong or what I am missing??

2
  • what if you do await searchListRequest.ExecuteAsync().ConfigureAwait(false)? Commented Mar 6, 2015 at 17:22
  • Thanks i3arnon, adding ' .ConfigureAwait(false) ' to the call worked! Awesome! Any thoughts as to why it's needed in the web application code but not in program console code?? Commented Mar 6, 2015 at 21:59

1 Answer 1

3

You seem to have a deadlock on your hands because you're doing "sync over async". When you use Task.Wait you're blocking and wasting a thread. After the inner async operation (i.e. await searchListRequest.ExecuteAsync();) completes it evidently needs that same thread to continue processing the rest of the method.

All that happens because of the SynchronizationContext present in ASP.Net which is captured when await is used so that the continuation would be posted to it. When you use ConfigureAwait(false) you're configuring the continuation to not run on the captured context and use the ThreadPool instead.

In console apps there is no SC and so every continuation runs on the ThreadPool. It's as if every await had ConfigureAwait(false).

To solve this deadlock you can use ConfigureAwait(false) or even better, make the MVC method async so you don't need to block synchronously (more on async in MVC):

public async Task<ActionResult> Index()
{
    ViewBag.Message = "MVC example";

    SearchYouTube searchObject = new SearchYouTube();
    await searchObject.RunYouTube();

    return View();
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you i3arnon, I have made the MVC method async and all is well! Appreciate the help!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.