被困了好几天,希望有人能帮助我。
在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();
}