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