Question

Comment utiliser HttpWebRequest (.NET, C #) de manière asynchrone?

Était-ce utile?

La solution

Utilisez HttpWebRequest.BeginGetResponse () <) / code>

HttpWebRequest webRequest;

void StartWebRequest()
{
    webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null);
}

void FinishWebRequest(IAsyncResult result)
{
    webRequest.EndGetResponse(result);
}

La fonction de rappel est appelée à la fin de l'opération asynchrone. Vous devez au moins appeler EndGetResponse () de cette fonction.

Autres conseils

Considérant la réponse:

HttpWebRequest webRequest;

void StartWebRequest()
{
    webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null);
}

void FinishWebRequest(IAsyncResult result)
{
    webRequest.EndGetResponse(result);
}

Vous pouvez envoyer le pointeur de requête ou tout autre objet comme celui-ci:

void StartWebRequest()
{
    HttpWebRequest webRequest = ...;
    webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), webRequest);
}

void FinishWebRequest(IAsyncResult result)
{
    HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
}

Salutations

Tout le monde s’est trompé jusqu’à présent, car BeginGetResponse () fonctionne avec le thread actuel. De la documentation :

  

La méthode BeginGetResponse nécessite certaines tâches d’installation synchrones pour   complète (résolution DNS, détection de proxy et connexion au socket TCP,   par exemple) avant que cette méthode ne devienne asynchrone. Par conséquent,   cette méthode ne doit jamais être appelée sur un thread d'interface utilisateur   parce que cela peut prendre beaucoup de temps (jusqu'à plusieurs minutes)   en fonction des paramètres du réseau) pour terminer la synchrone initiale   tâches de configuration avant qu'une exception pour une erreur soit levée ou la méthode   réussit.

Donc, pour faire cela correctement:

void DoWithResponse(HttpWebRequest request, Action<HttpWebResponse> responseAction)
{
    Action wrapperAction = () =>
    {
        request.BeginGetResponse(new AsyncCallback((iar) =>
        {
            var response = (HttpWebResponse)((HttpWebRequest)iar.AsyncState).EndGetResponse(iar);
            responseAction(response);
        }), request);
    };
    wrapperAction.BeginInvoke(new AsyncCallback((iar) =>
    {
        var action = (Action)iar.AsyncState;
        action.EndInvoke(iar);
    }), wrapperAction);
}

Vous pouvez ensuite faire ce dont vous avez besoin avec la réponse. Par exemple:

HttpWebRequest request;
// init your request...then:
DoWithResponse(request, (response) => {
    var body = new StreamReader(response.GetResponseStream()).ReadToEnd();
    Console.Write(body);
});

Le moyen le plus simple est de loin d'utiliser TaskFactory.FromAsync à partir du TPL . C'est littéralement quelques lignes de code lorsqu'il est utilisé avec le nouveau async / wait mots clés:

var request = WebRequest.Create("http://www.stackoverflow.com");
var response = (HttpWebResponse) await Task.Factory
    .FromAsync<WebResponse>(request.BeginGetResponse,
                            request.EndGetResponse,
                            null);
Debug.Assert(response.StatusCode == HttpStatusCode.OK);

Si vous ne pouvez pas utiliser le compilateur C # 5, vous pouvez réaliser ce qui précède à l'aide de Méthode Task.ContinueWith :

Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse,
                                    request.EndGetResponse,
                                    null)
    .ContinueWith(task =>
    {
        var response = (HttpWebResponse) task.Result;
        Debug.Assert(response.StatusCode == HttpStatusCode.OK);
    });

J'ai fini par utiliser BackgroundWorker, il est définitivement asynchrone contrairement à certaines des solutions ci-dessus, il gère le retour au fil de l'interface graphique pour vous, et il est très facile à comprendre.

Il est également très facile de gérer les exceptions, car elles se retrouvent dans la méthode RunWorkerCompleted, mais veillez à lire ceci: Exceptions non gérées dans BackgroundWorker

J'ai utilisé WebClient, mais vous pouvez évidemment utiliser HttpWebRequest.GetResponse si vous le souhaitez.

var worker = new BackgroundWorker();

worker.DoWork += (sender, args) => {
    args.Result = new WebClient().DownloadString(settings.test_url);
};

worker.RunWorkerCompleted += (sender, e) => {
    if (e.Error != null) {
        connectivityLabel.Text = "Error: " + e.Error.Message;
    } else {
        connectivityLabel.Text = "Connectivity OK";
        Log.d("result:" + e.Result);
    }
};

connectivityLabel.Text = "Testing Connectivity";
worker.RunWorkerAsync();

.NET a changé depuis la publication de bon nombre de ces réponses, et j'aimerais vous donner une réponse plus à jour. Utilisez une méthode asynchrone pour démarrer une tâche qui s'exécutera sur un thread en arrière-plan:

private async Task<String> MakeRequestAsync(String url)
{    
    String responseText = await Task.Run(() =>
    {
        try
        {
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            WebResponse response = request.GetResponse();            
            Stream responseStream = response.GetResponseStream();
            return new StreamReader(responseStream).ReadToEnd();            
        }
        catch (Exception e)
        {
            Console.WriteLine("Error: " + e.Message);
        }
        return null;
    });

    return responseText;
}

Pour utiliser la méthode asynchrone:

String response = await MakeRequestAsync("http://example.com/");

Mise à jour:

Cette solution ne fonctionne pas pour les applications UWP utilisant WebRequest.GetResponseAsync () au lieu de WebRequest.GetResponse () et n'appelle pas . () méthodes, le cas échéant. @dragansr a une bonne solution alternative à ces problèmes.

public void GetResponseAsync (HttpWebRequest request, Action<HttpWebResponse> gotResponse)
    {
        if (request != null) { 
            request.BeginGetRequestStream ((r) => {
                try { // there's a try/catch here because execution path is different from invokation one, exception here may cause a crash
                    HttpWebResponse response = request.EndGetResponse (r);
                    if (gotResponse != null) 
                        gotResponse (response);
                } catch (Exception x) {
                    Console.WriteLine ("Unable to get response for '" + request.RequestUri + "' Err: " + x);
                }
            }, null);
        } 
    }
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);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top