异步httpclient操作

时间:2014-05-16 23:37:44

标签: c# asynchronous

我正在尝试设计一个以编程方式获取网站更新的浏览器。我试图用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#

是新的问题

3 个答案:

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