在ASP.NET MVC4中使用Google API YouTube搜索示例



被困了好几天,希望有人能帮助我。

在VS 2013 Express for Web MVC4项目中,我一直在尝试从Google的API examples for.net运行YouTube"按关键字搜索"示例,而调用Google API的ExecuteAsync()永远不会回来。

我相信示例代码是有效的,因为我在VS2013ExpressforWindowsDesktop中测试了它作为控制台应用程序,结果很好。此外,谷歌开发者控制台中的统计数据告诉我API请求正在收到。

以下是我所做的:

我创建了一个新的VS2013ExpressforWebMVC4项目,名为GoogleTest,并安装了"安装包Google.Apis.YouTube.v3"。

然后我添加了以下模型。

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

然后我在家庭控制器中调用上面的类,如下所示:

public ActionResult Index()
{
    ViewBag.Message = "MVC example";
    SearchYouTube searchObject = new SearchYouTube();
    searchObject.RunYouTube().Wait();
    return View();
}

在调试器中运行此程序时,程序会进入上面的SearchYouTube类中的这一行,但永远不会返回:

var searchListResponse = await searchListRequest.ExecuteAsync();

有人能帮我解释一下我做错了什么或错过了什么吗??

您似乎有一个死锁,因为您正在执行"异步同步"。当您使用Task.Wait时,您会阻塞并浪费线程。在内部async操作(即await searchListRequest.ExecuteAsync();)完成后,它显然需要相同的线程来继续处理该方法的其余部分。

所有这些都是因为ASP.Net中存在SynchronizationContext,它是在使用await时捕获的,以便将延续发布到它。当您使用ConfigureAwait(false)时,您将延续配置为不在捕获的上下文上运行,而是使用ThreadPool

在控制台应用程序中没有SC,因此每个延续都在ThreadPool上运行。就好像每个await都有ConfigureAwait(false)

为了解决这个死锁,你可以使用ConfigureAwait(false),甚至更好,让MVC方法async,这样你就不需要同步阻塞(更多关于MVC中的async):

public async Task<ActionResult> Index()
{
    ViewBag.Message = "MVC example";
    SearchYouTube searchObject = new SearchYouTube();
    await searchObject.RunYouTube();
    return View();
}

最新更新