2014-05-16 1 views
5

J'essaye de concevoir un navigateur qui récupérera des mises à jour de site par programme. J'essaye de faire ceci avec des méthodes async/await mais quand j'essaye et exécute le programme il semble juste se bloquer sur response.Wait() ;. Je ne sais pas pourquoi ou ce qui se passe.async httpclient operation

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

classe navigateur ::

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

En outre, pour mes fins prévues, il est autorisé à faire navigateur une fonction statique, ou est-ce que pas de sens? Désolé pour les questions, nouveau à C#

+0

Est-ce qu'il vous permettra de faire MainWindow() 'une méthode' async'? Si vous pouvez alors vous pouvez simplement attendre à la place. Je suis assez sûr que 'Task.Wait()' est une méthode de blocage. – pquest

+0

J'étais sous l'impression que mainwindow() est l'équivalent principal() dans WPF, donc c'est une méthode de blocage est attendue. – cubesnyc

+0

J'ai modifié votre titre. S'il vous plaît voir, "[Les questions devraient inclure" tags "dans leurs titres?] (Http://meta.stackoverflow.com/questions/19190/)", où le consensus est "non, ils ne devraient pas". –

Répondre

1

Il est une mauvaise idée d'appeler Wait sur un Task dans un thread d'interface utilisateur, il en résulte une impasse. Vous pouvez simplement await la réponse qui permettra d'atteindre ce que vous voulez. Le await déballe la réponse du Task pour que votre type de retour soit maintenant juste HttpResponseMessage. Comme vous ne pouvez pas marquer les constructeurs comme async, vous pouvez déplacer la fonctionnalité vers une autre méthode qui déclenche l'opération.

public MainWindow() 
{ 
    InitializeComponent(); 
    LoadUrlsAsync(); 
} 

public async Task LoadUrlsAsync() 
{ 
    var urls = sourceUrls(); 
    HttpResponseMessage response = await login(urls[0]); 

    Console.Write("Complete"); 
} 

Voir this article pour les meilleures pratiques lors de l'utilisation async/await.

Vous pouvez également utiliser la méthode d'extension Task.ConfigureAwait pour configurer la suite de ne pas exécuter sur le SyncrhronizationContext actuel qui devrait également éviter l'interblocage.

public MainWindow() 
{ 
    InitializeComponent(); 

    var urls = sourceUrls(); 
    Task<HttpResponseMessage> response = login(urls[0]).ConfigureAwait(false); 
    response.Wait(); 

    Console.Write("Complete"); 
} 
+1

Mainwindow ne peut pas être déclaré asynchrone, et donc votre premier exemple ne fonctionnera pas. – cubesnyc

+0

merci, fixé maintenant. –

0

Les deux GetUrl() et GetUrl2(), ci-dessous, accomplissent ce que vous cherchez à faire de manière légèrement différente. Sachez toutefois que Task.Wait bloquera le thread en cours (dans ce cas, le thread de l'interface utilisateur) jusqu'à ce que la tâche se termine. Je suppose que ce n'est pas ce que tu veux faire.

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

Wait provoque a deadlock that I explain in full on my blog. La meilleure solution est d'utiliser await comme Ned suggéré.

Dans votre cas, les constructeurs ne peuvent pas être async, ce n'est donc pas possible. Cela devrait indiquer que ce que vous essayez de faire n'est peut-être pas la meilleure chose à faire. En particulier, vous essayez de bloquer le thread d'interface utilisateur en attente d'un téléchargement à compléter; Ce n'est presque jamais une bonne idée.

Au lieu de cela, demandez à votre constructeur commencer l'opération asynchrone et (synchrone) charger une vue qui montre aucune donnée - par exemple, un écran « chargement » ou une vue vide, tout ce qui fait le plus de sens pour votre domaine de problème. Ensuite, lorsque l'opération asynchrone est terminée, elle doit mettre à jour la vue avec les nouvelles données. J'ai un article sur async data binding qui explore une technique possible.