我正在尝试设计一个以编程方式获取网站更新的浏览器。我试图用async / await方法做这个,但是当我尝试运行程序时,它似乎只是挂在response.Wait();.不知道为什么或者发生了什么。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var urls = sourceUrls();
Task<HttpResponseMessage> response = login(urls[0]);
response.Wait();
Console.Write( "Complete" );
}
private List<Site> sourceUrls()
{
var urls = new List<Site>();
urls.Add(new Site("http://yahoo.com", "test", "test"));
return urls;
}
}
浏览器类::
static public class Browser
{
private static CookieContainer cc = new CookieContainer();
private static HttpClientHandler handler = new HttpClientHandler();
public static HttpClient browser = new HttpClient(handler);
static Browser()
{
handler.CookieContainer = cc;
}
static public async Task<HttpResponseMessage> login(Site site)
{
var _postData = new Dictionary<string, string>
{
{"test", "test"}
};
FormUrlEncodedContent postData = new FormUrlEncodedContent(_postData);
HttpResponseMessage response = await browser.PostAsync(site.url, postData);
return response;
}
}
另外,对于我的预期目的,是否可以使浏览器成为静态功能,或者这是否有意义?对不起,c#
是新的问题答案 0 :(得分:1)
在UI线程中的Wait
上调用Task
是一个坏主意,它会导致死锁。
您只需await
即可实现您想要的响应。 await
取消Task
的响应,因此您的返回类型现在只有HttpResponseMessage
。因为您无法将构造函数标记为async
,所以您可以将该功能移动到另一个启动操作的方法。
public MainWindow()
{
InitializeComponent();
LoadUrlsAsync();
}
public async Task LoadUrlsAsync()
{
var urls = sourceUrls();
HttpResponseMessage response = await login(urls[0]);
Console.Write( "Complete" );
}
使用async/await
时,请参阅this文章了解最佳做法。
或者,您可以使用Task.ConfigureAwait
扩展方法将延续配置为不在当前SyncrhronizationContext
上运行,这也应该避免死锁。
public MainWindow()
{
InitializeComponent();
var urls = sourceUrls();
Task<HttpResponseMessage> response = login(urls[0]).ConfigureAwait(false);
response.Wait();
Console.Write( "Complete" );
}
答案 1 :(得分:1)
Wait
导致a deadlock that I explain in full on my blog。最好的解决方案是使用await
作为Ned的建议。
在您的情况下,构造函数不能是async
,因此不可能。这应该表明您尝试做的事情可能不是最好的事情。特别是,您正试图阻止等待下载完成的UI线程;这几乎不是一个好主意。
相反,让构造函数启动异步操作并(同步)加载一个不显示数据的视图 - 例如,&#34; loading&#34;屏幕或空视图,对您的问题域最有意义。然后,当异步操作完成时,它应该使用新数据更新视图。我有一篇关于async
data binding的文章,探讨了一种可能的技术。
答案 2 :(得分:0)
下面的GetUrl()
和GetUrl2()
都会以稍微不同的方式完成您要做的事情。但请注意,Task.Wait将阻止当前线程(在本例中为UI线程),直到任务完成。我猜这不是你想要做的。
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
GetUrls();
GetUrls2();
}
private void GetUrls()
{
var response = Task.Run(() => Browser.login("http://yahoo.com"));
response.Wait();
Debug.WriteLine("Complete GetUrls()");
}
private void GetUrls2()
{
var browseTask = Browser.login("http://yahoo.com");
browseTask.ContinueWith((r) => Debug.WriteLine("Complete GetUrls2()"));
}
}
static public class Browser
{
static public async Task<HttpResponseMessage> login(string site)
{
var browser = new HttpClient();
return await browser.GetAsync(site);
}
}