如何asynchronous使用HttpWebRequest(.NET)?
我如何asynchronous使用HttpWebRequest(.NET,C#)?
使用HttpWebRequest.BeginGetResponse()
HttpWebRequest webRequest; void StartWebRequest() { webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null); } void FinishWebRequest(IAsyncResult result) { webRequest.EndGetResponse(result); }
callback函数在asynchronous操作完成时被调用。 你至less需要从这个函数调用EndGetResponse()
。
考虑到答案:
HttpWebRequest webRequest; void StartWebRequest() { webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null); } void FinishWebRequest(IAsyncResult result) { webRequest.EndGetResponse(result); }
你可以发送请求指针或任何其他对象像这样:
void StartWebRequest() { HttpWebRequest webRequest = ...; webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), webRequest); } void FinishWebRequest(IAsyncResult result) { HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse; }
问候
到目前为止,所有人都错了,因为BeginGetResponse()
在当前线程上做了一些工作。 从文档 :
在此方法变为asynchronous之前,BeginGetResponse方法需要完成一些同步设置任务(例如DNSparsing,代理检测和TCP套接字连接)。 因此,不应该在用户界面(UI)线程上调用此方法,因为在抛出错误之前可能需要花费相当长的时间(取决于networking设置长达几分钟)才能完成初始同步设置任务,或者该方法成功。
所以要做到这一点的权利:
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); }
然后你可以做你需要的回应。 例如:
HttpWebRequest request; // init your request...then: DoWithResponse(request, (response) => { var body = new StreamReader(response.GetResponseStream()).ReadToEnd(); Console.Write(body); });
到目前为止,最简单的方法是使用TPL中的 TaskFactory.FromAsync 。 当与新的async / await关键字结合使用时,实际上是几行代码:
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);
如果您不能使用C#5编译器,则可以使用Task.ContinueWith方法完成上述操作 :
Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null) .ContinueWith(task => { var response = (HttpWebResponse) task.Result; Debug.Assert(response.StatusCode == HttpStatusCode.OK); });
我最终使用了BackgroundWorker,与上面的一些解决scheme完全是asynchronous的,它为您处理返回到GUI线程,这是很容易理解的。
处理exception也很容易,因为它们最终在RunWorkerCompleted方法中,但请确保您阅读: BackgroundWorker中未处理的exception
我使用WebClient,但显然你可以使用HttpWebRequest.GetResponse如果你想。
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 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); } }
.NET已经改变,因为这些答案已经发布了,我想提供一个更新的答案。 使用asynchronous方法启动将在后台线程上运行的Task
:
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; }
要使用asynchronous方法:
String response = await MakeRequestAsync("http://example.com/");