Wie kann ich HttpWebRequest (.NET, C #) asynchron verwenden?
Wie kann ich HttpWebRequest (.NET, C #) asynchron verwenden?
Antworten:
Verwenden 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 .
webRequest.Proxy = null, um die Anforderung drastisch zu beschleunigen.
Betrachtet man die 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 folgt 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
Bisher haben sich alle geirrt, weil BeginGetResponse()einige am aktuellen Thread arbeiten. Aus der Dokumentation :
Für die BeginGetResponse-Methode müssen einige synchrone Setup-Aufgaben ausgeführt werden (z. B. DNS-Auflösung, Proxy-Erkennung und TCP-Socket-Verbindung), bevor diese Methode asynchron wird. Daher sollte diese Methode niemals in einem UI-Thread (User Interface) aufgerufen werden, da es einige Zeit (bis zu mehreren Minuten, abhängig von den Netzwerkeinstellungen) dauern kann, bis die anfänglichen synchronen Setup-Aufgaben abgeschlossen sind, bevor eine Ausnahme für einen Fehler ausgelöst wird oder Die Methode ist erfolgreich.
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);
}
Mit der Antwort können Sie dann tun, was Sie brauchen. Beispielsweise:
HttpWebRequest request;
// init your request...then:
DoWithResponse(request, (response) => {
var body = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.Write(body);
});
Der mit Abstand einfachste Weg ist die Verwendung von TaskFactory.FromAsync aus der 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 oben genannten 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);
});
Am Ende habe ich BackgroundWorker verwendet. Im Gegensatz zu einigen der oben genannten Lösungen ist es definitiv asynchron. Es übernimmt die Rückkehr zum GUI-Thread für Sie und ist sehr einfach zu verstehen.
Es ist auch sehr einfach, Ausnahmen zu behandeln, 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();
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);
}
.NET hat sich geändert, seit viele dieser Antworten veröffentlicht wurden, und ich möchte eine aktuellere Antwort geben. Verwenden Sie eine asynchrone Methode, um eine Methode zu starten Task, die 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/");
Aktualisieren:
Diese Lösung funktioniert nicht für UWP-Apps, die WebRequest.GetResponseAsync()anstelle von verwenden WebRequest.GetResponse(), und ruft die Dispose()Methoden gegebenenfalls nicht auf. @dragansr hat eine gute alternative Lösung, die diese Probleme behebt.
WebRequest.GetResponseAsync()und StreamReader.ReadToEndAync()müssen verwendet werden und abgewartet.
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);
}
}