161 votes

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

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

2 votes

Consultez cet article sur Developer Fusion : developerfusion.com/code/4654/asynchronous-httpwequest

0 votes

Vous pouvez également voir ce qui suit, pour un exemple assez complet de ce que Jason demande : stuff.seans.com/2009/01/05/ Sean

1 votes

Utiliser l'asynchronisme msdn.microsoft.com/fr/us/library/

128voto

Jon B Points 26872

Utilisez HttpWebRequest.BeginGetResponse()

HttpWebRequest webRequest;

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

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

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

16 votes

BeginGetResponse n'est pas très utile pour une utilisation asynchrone. Il semble se bloquer lorsqu'il essaie de contacter la ressource. Essayez de débrancher votre câble réseau ou de lui donner une uri malformée, puis exécutez ce code. Au lieu de cela, vous devez probablement exécuter GetResponse sur un deuxième thread que vous fournissez.

2 votes

@AshleyHenderson - Pourriez-vous me fournir un échantillon ?

1 votes

@Tohid Voici un cours complet avec un échantillon J'ai utilisé avec Unity3D.

71voto

Nathan Baulch Points 7994

Le moyen le plus simple, et de loin, est d'utiliser TaskFactory.FromAsync de la TPL . Il s'agit littéralement de quelques lignes de code lorsqu'elles sont utilisées en conjonction avec la nouvelle fonction async/await 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, ce qui précède peut être accompli en utilisant la fonction Task.ContinueWith méthode :

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

0 votes

Depuis .NET 4, cette approche TAP est préférable. Voir un exemple similaire de MS - "How to : Wrap EAP Patterns in a Task" ( msdn.microsoft.com/fr/us/library/ee622454.aspx )

0 votes

Bien plus facile que les autres moyens

67voto

xlarsx Points 745

En 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 la demande ou tout autre objet comme ceci :

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

7 votes

+1 pour l'option qui ne dépasse pas la portée de la variable 'request', mais vous auriez pu faire un cast au lieu d'utiliser le mot clé "as". Une InvalidCastException aurait été levée au lieu d'une NullReferenceException confuse.

64voto

Isak Points 330

Tout le monde a eu tort jusqu'à présent, parce que BeginGetResponse() effectue un travail sur le fil actuel. Du documentation :

La méthode BeginGetResponse nécessite quelques tâches de configuration synchrones pour (résolution DNS, détection de proxy et connexion de 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 (IU) car cela pourrait prendre un temps considérable (jusqu'à plusieurs minutes (jusqu'à plusieurs minutes, selon les paramètres du réseau) pour effectuer les synchrones avant qu'une exception soit levée ou que la méthode réussisse. ne réussisse.

Donc pour faire ça bien :

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 que vous voulez de la réponse. Par exemple :

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

2 votes

Ne pourriez-vous pas simplement appeler la méthode GetResponseAsync de HttpWebRequest en utilisant await (en supposant que vous ayez rendu votre fonction asynchrone) ? Je suis très novice en C#, donc il se peut que ce soit du charabia...

0 votes

GetResponseAsync semble être une bonne solution, mais vous aurez besoin de .NET 4.5 (actuellement en version bêta).

16 votes

Jésus. C'est un code affreux. Pourquoi le code asynchrone ne peut-il pas être lisible ?

7voto

eggbert Points 516

J'ai fini par utiliser BackgroundWorker, il est définitivement asynchrone contrairement à certaines des solutions ci-dessus, il gère le retour au thread 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 aboutissent dans la méthode RunWorkerCompleted, mais assurez-vous de 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();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X