提问人:Jason 提问时间:10/15/2008 最后编辑:FerruccioJason 更新时间:1/18/2022 访问量:196630
如何异步使用 HttpWebRequest (.NET)?
How to use HttpWebRequest (.NET) asynchronously?
答:
使用 HttpWebRequest.BeginGetResponse()
HttpWebRequest webRequest;
void StartWebRequest()
{
webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null);
}
void FinishWebRequest(IAsyncResult result)
{
webRequest.EndGetResponse(result);
}
异步操作完成时调用回调函数。您至少需要从此函数调用 EndGetResponse()。
评论
webRequest.Proxy = null
考虑答案:
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;
}
问候
评论
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);
}
}
到目前为止,每个人都错了,因为在当前线程上做了一些工作。从文档中:BeginGetResponse()
BeginGetResponse 方法需要一些同步安装任务才能 完成(DNS解析、代理检测、TCP套接字连接、 例如),在此方法变为异步之前。因此, 不应在用户界面 (UI) 线程上调用此方法 因为它可能需要相当长的时间(最多几分钟 取决于网络设置)以完成初始同步 在引发错误异常或方法之前设置任务 成功。
因此,要做到这一点:
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);
});
评论
我最终使用了 BackgroundWorker,与上述一些解决方案不同,它绝对是异步的,它为您处理返回到 GUI 线程,并且非常容易理解。
处理异常也非常容易,因为它们最终会出现在 RunWorkerCompleted 方法中,但请务必阅读以下内容:BackgroundWorker 中未处理的异常
我使用了 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();
到目前为止,最简单的方法是使用 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);
});
评论
自从发布其中许多答案以来,.NET 发生了变化,我想提供一个更新的答案。使用异步方法启动将在后台线程上运行的: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;
}
要使用 async 方法,请执行以下操作:
String response = await MakeRequestAsync("http://example.com/");
更新:
此解决方案不适用于使用 代替 的 UWP 应用,并且不会在适当的情况下调用这些方法。@dragansr 有一个很好的替代解决方案来解决这些问题。WebRequest.GetResponseAsync()
WebRequest.GetResponse()
Dispose()
评论
WebRequest.GetResponseAsync()
StreamReader.ReadToEndAync()
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);
}
跟进@Isak的回答,很不错。尽管如此,它最大的缺陷是,只有当响应的状态为 200-299 时,它才会调用 responseAction。解决此问题的最佳方法是:
private void DoWithResponseAsync(HttpWebRequest request, Action<HttpWebResponse> responseAction)
{
Action wrapperAction = () =>
{
request.BeginGetResponse(new AsyncCallback((iar) =>
{
HttpWebResponse response;
try
{
response = (HttpWebResponse)((HttpWebRequest)iar.AsyncState).EndGetResponse(iar);
}
catch (WebException ex)
{
// It needs to be done like this in order to read responses with error status:
response = ex.Response as HttpWebResponse;
}
responseAction(response);
}), request);
};
wrapperAction.BeginInvoke(new AsyncCallback((iar) =>
{
var action = (Action)iar.AsyncState;
action.EndInvoke(iar);
}), wrapperAction);
}
然后如下@Isak:
HttpWebRequest request;
// init your request...then:
DoWithResponse(request, (response) => {
var body = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.Write(body);
});
我一直在将其用于异步 UWR,希望它对某人有所帮助
string uri = "http://some.place.online";
using (UnityWebRequest uwr = UnityWebRequest.Get(uri))
{
var asyncOp = uwr.SendWebRequest();
while (asyncOp.isDone == false) await Task.Delay(1000 / 30); // 30 hertz
if(uwr.result == UnityWebRequest.Result.Success) return uwr.downloadHandler.text;
Debug.LogError(uwr.error);
}
评论