web-dev-qa-db-fra.com

Obtenir la réponse d'un HttpWebRequest asynchrone

Je me demande s'il existe un moyen simple d'obtenir la réponse d'un httpwebrequest asynchrone.

J'ai déjà vu cette question ici mais tout ce que j'essaie de faire est de renvoyer la réponse (qui est généralement json ou xml) sous la forme d'une chaîne de caractères à une autre méthode où je peux ensuite l'analyser/la traiter en conséquence.

Heres du code:

J'ai ces deux méthodes statiques ici que je pense sont thread-safe car tous les paramètres sont passés et il n'y a pas de variables locales partagées que les méthodes utilisent?

public static void MakeAsyncRequest(string url, string contentType)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.ContentType = contentType;
    request.Method = WebRequestMethods.Http.Get;
    request.Timeout = 20000;
    request.Proxy = null;

    request.BeginGetResponse(new AsyncCallback(ReadCallback), request);
}

private static void ReadCallback(IAsyncResult asyncResult)
{
    HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
    try
    {
        using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult))
        {
            Stream responseStream = response.GetResponseStream();
            using (StreamReader sr = new StreamReader(responseStream))
            {
                //Need to return this response 
                string strContent = sr.ReadToEnd();
            }
       }
       manualResetEvent.Set();
    }
    catch (Exception ex)
    {
        throw ex;
   }
}
18
gdp

En supposant que le problème vienne du contenu renvoyé, le chemin le plus simple serait probablement d'utiliser async/wait si vous pouvez l'utiliser. Encore mieux serait de passer à HttpClient si vous utilisez .NET 4.5, car il est asynchrone de manière «native».

En utilisant .NET 4 et C # 4, vous pouvez toujours utiliser Task pour les encapsuler et faciliter l'accès au résultat final. Par exemple, une option serait la suivante. Notez que la méthode Main est bloquée jusqu'à ce que la chaîne de contenu soit disponible, mais dans un scénario "réel", il est probable que vous passiez la tâche à autre chose ou que vous en fassiez une autre par la suite.

void Main()
{
    var task = MakeAsyncRequest("http://www.google.com", "text/html");
    Console.WriteLine ("Got response of {0}", task.Result);
}

// Define other methods and classes here
public static Task<string> MakeAsyncRequest(string url, string contentType)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.ContentType = contentType;
    request.Method = WebRequestMethods.Http.Get;
    request.Timeout = 20000;
    request.Proxy = null;

    Task<WebResponse> task = Task.Factory.FromAsync(
        request.BeginGetResponse,
        asyncResult => request.EndGetResponse(asyncResult),
        (object)null);

    return task.ContinueWith(t => ReadStreamFromResponse(t.Result));
}

private static string ReadStreamFromResponse(WebResponse response)
{
    using (Stream responseStream = response.GetResponseStream())
    using (StreamReader sr = new StreamReader(responseStream))
    {
        //Need to return this response 
        string strContent = sr.ReadToEnd();
        return strContent;
    }
}
41
James Manning

"Encore mieux serait de passer à HttpClient si vous utilisez .NET 4.5 car il est" nativement "async." - Réponse tout à fait juste de James Manning… .. Cette question a été posée il y a environ 2 ans. Nous avons maintenant .NET Framework 4.5, qui fournit de puissantes méthodes asynchrones. Utilisez HttpClient. Considérons le code suivant:

 async Task<string> HttpGetAsync(string URI)
    {
        try
        {
            HttpClient hc = new HttpClient();
            Task<Stream> result = hc.GetStreamAsync(URI);

            Stream vs = await result;
            StreamReader am = new StreamReader(vs);

            return await am.ReadToEndAsync();
        }
        catch (WebException ex)
        {
            switch (ex.Status)
            {
                case WebExceptionStatus.NameResolutionFailure:
                    MessageBox.Show("domain_not_found", "ERROR",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                break;
                    //Catch other exceptions here
            }
        }
    }

Pour utiliser HttpGetAsync (), créez une nouvelle méthode également "asynchrone". async est requis, car nous devons utiliser "wait" dans la méthode GetWebPage ():

async void GetWebPage(string URI)
        {
            string html = await HttpGetAsync(URI);
            //Do other operations with html code
        }

Désormais, si vous souhaitez obtenir le code source HTML d'une page Web de manière asynchrone, appelez simplement GetWebPage ("adresse Web ..."). Même la lecture de flux est asynchrone.

REMARQUE: pour utiliser HttpClient .NET Framework 4.5 est requis. Vous devez également ajouter la référence System.Net.Http à votre projet et ajouter également "using System.Net.Http" pour un accès facile.

Pour en savoir plus sur le fonctionnement de cette approche, visitez le site: http://msdn.Microsoft.com/en-us/library/hh191443(v=vs.110).aspx

Utilisation de Async: Async dans la version 4.5: vaut la peine d'attendre

6
mirushaki

Une fois async, vous ne pouvez plus revenir en arrière. De là, vous avez vraiment accès au rappel de l'async. vous pouvez augmenter la complexité de cette situation et faire quelques pas de file d'attente, mais cela peut être un effort plutôt pénible.

Techniquement, vous pouvez également mettre le thread en veille lorsque vous devez attendre les résultats, mais je ne le recommande pas. Vous pouvez également effectuer une demande http normale à ce stade.

En C # 5, ils ont des commandes async/wait qui faciliteront l’obtention des résultats de l’appel async sur le thread principal.

2
Thinking Sites
public static async Task<byte[]> GetBytesAsync(string url) {
    var request = (HttpWebRequest)WebRequest.Create(url);
    using (var response = await request.GetResponseAsync())
    using (var content = new MemoryStream())
    using (var responseStream = response.GetResponseStream()) {
        await responseStream.CopyToAsync(content);
        return content.ToArray();
    }
}

public static async Task<string> GetStringAsync(string url) {
    var bytes = await GetBytesAsync(url);
    return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
0
dragansr