it-swarm.com.de

Wie verwende ich HttpWebRequest (.NET) asynchron?

Wie kann ich HttpWebRequest (.NET, C #) asynchron verwenden?

149
Jason

Verwenden Sie HttpWebRequest.BeginGetResponse()

HttpWebRequest webRequest;

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

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

Die Rückruffunktion wird aufgerufen, wenn der asynchrone Vorgang abgeschlossen ist. Sie müssen mindestens EndGetResponse() von dieser Funktion aus aufrufen.

121
Jon B

In Anbetracht der Antwort:

HttpWebRequest webRequest;

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

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

Sie können den Anforderungszeiger oder ein anderes Objekt wie das folgende senden:

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

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

Schöne Grüße

65
xlarsx

Bisher haben sich alle geirrt, weil BeginGetResponse() am aktuellen Thread etwas arbeitet. Aus der Dokumentation :

Für die BeginGetResponse-Methode müssen einige synchrone Setup-Aufgaben ausgeführt werden (DNS-Auflösung, Proxyerkennung und TCP Socket-Verbindung)), bevor diese Methode asynchron wird. Aus diesem Grund sollte diese Methode niemals aufgerufen werden auf einem Benutzeroberflächenthread, da die Ausführung der ersten synchronen Setup-Aufgaben möglicherweise einige Zeit in Anspruch nimmt (abhängig von den Netzwerkeinstellungen bis zu mehreren Minuten), bevor eine Ausnahme für einen Fehler ausgelöst wird oder die Methode erfolgreich ist.

Um dies richtig zu machen:

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

Sie können dann mit der Antwort das tun, was Sie brauchen. Beispielsweise:

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

Bei weitem der einfachste Weg ist die Verwendung von TaskFactory.FromAsync aus TPL . In Verbindung mit den neuen Schlüsselwörtern async/await sind es buchstäblich ein paar Codezeilen:

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

Wenn Sie den C # 5-Compiler nicht verwenden können, können Sie die obigen Schritte mit der Task.ContinueWith -Methode ausführen:

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

Am Ende habe ich BackgroundWorker verwendet. Es ist definitiv asynchron, im Gegensatz zu einigen der oben genannten Lösungen. Es behandelt die Rückkehr zum GUI-Thread für Sie und ist sehr einfach zu verstehen.

Es ist auch sehr einfach, mit Ausnahmen umzugehen, da sie in der RunWorkerCompleted-Methode enden. Lesen Sie jedoch Folgendes: Nicht behandelte Ausnahmen in BackgroundWorker

Ich habe WebClient verwendet, aber natürlich können Sie HttpWebRequest.GetResponse verwenden, wenn Sie möchten.

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();
7
eggbert

.NET hat sich geändert, seit viele dieser Antworten veröffentlicht wurden, und ich möchte eine aktuellere Antwort bereitstellen. Verwenden Sie eine asynchrone Methode, um ein Task zu starten, das in einem Hintergrundthread ausgeführt wird:

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

So verwenden Sie die asynchrone Methode:

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

pdate:

Diese Lösung funktioniert nicht für UWP-Apps, die WebRequest.GetResponseAsync() anstelle von WebRequest.GetResponse() verwenden, und ruft gegebenenfalls die Dispose() -Methoden nicht auf. @dragansr hat eine gute alternative Lösung, die diese Probleme behebt.

5
tronman
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);
        } 
    }
3
Sten Petrov
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);
}
3
dragansr