如何在不中断async / await的情况下创建HttpWebRequest?
我有一堆慢function,基本上是这样的:
private async Task<List> DownloadSomething() { var request = System.Net.WebRequest.Create("https://valid.url"); ... using (var ss = await request.GetRequestStreamAsync()) { await ss.WriteAsync(...); } using (var rr = await request.GetResponseAsync()) using (var ss = rr.GetResponseStream()) { //read stream and return data } }
除了调用WebRequest.Create
之外,这很好地和异步地工作 – 这一行将UI线程冻结几秒钟,这会破坏async / await的目的。
我已经使用BackgroundWorker
编写了这个代码,它完美运行并且永远不会冻结UI。
但是, 创建与async / await相关的Web请求的正确,惯用方法是什么? 或者也许应该使用另一个类?
我已经看到了关于异步化WebRequest
这个很好的答案 ,但即使在那里,对象本身也是同步创建的。
有趣的是,我没有看到使用WebRequest.Create
或HttpClient.PostAsync
的阻塞延迟。 它可能与DNS解析或代理配置有关,尽管我也希望这些操作在内部实现为异步。
无论如何,作为一种解决方法,你可以在池线程上启动请求,虽然这不是我通常做的事情:
private async Task> DownloadSomething() { var request = await Task.Run(() => { // WebRequest.Create freezes?? return System.Net.WebRequest.Create("https://valid.url"); }); // ... using (var ss = await request.GetRequestStreamAsync()) { await ss.WriteAsync(...); } using (var rr = await request.GetResponseAsync()) using (var ss = rr.GetResponseStream()) { //read stream and return data } }
这将使UI保持响应,但如果用户想要停止操作,则可能很难取消它。 那是因为您需要已经有一个WebRequest
实例才能在其上调用Abort
。
使用HttpClient
,可以取消,如下所示:
private async Task> DownloadSomething(CancellationToken token) { var httpClient = new HttpClient(); var response = await Task.Run(async () => { return await httpClient.PostAsync("https://valid.url", token); }, token); // ... }
使用HttpClient
,您还可以在取消令牌上注册httpClient.CancelPendingRequests()
回调,如下所示 。
[更新]根据评论:在您的原始情况下(在介绍Task.Run
之前),您可能不需要IProgress
模式。 只要在UI线程上调用了DownloadSomething()
,每个await
DownloadSomething
内部的每个执行步骤都将在同一个UI线程上恢复,因此您可以直接在awaits
之间更新UI。
现在,要在池线程上通过Task.Run
运行整个DownloadSomething()
,您必须将IProgress
的实例传递给它,例如:
private async Task> DownloadSomething( string url, IProgress progress, CancellationToken token) { var request = System.Net.WebRequest.Create(url); // ... using (var ss = await request.GetRequestStreamAsync()) { await ss.WriteAsync(...); } using (var rr = await request.GetResponseAsync()) using (var ss = rr.GetResponseStream()) { // read stream and return data progress.Report(...); // report progress } } // ... // Calling DownloadSomething from the UI thread via Task.Run: var progressIndicator = new Progress (ReportProgress); var cts = new CancellationTokenSource(30000); // cancel in 30s (optional) var url = "https://valid.url"; var result = await Task.Run(() => DownloadSomething(url, progressIndicator, cts.Token), cts.Token); // the "result" type is deduced to "List" by the compiler
注意,因为DownloadSomething
本身就是一个async
方法,所以它现在作为嵌套任务运行, Task.Run
透明地为你解开。 更多相关信息: Task.Run vs Task.Factory.StartNew 。
另请参阅: 在异步API中启用进度和取消 。
我认为您需要使用HttpClient.GetAsync()从HTTP请求返回任务。
https://msdn.microsoft.com/en-us/library/hh158912(v=vs.110).aspx
它可能取决于您想要返回的内容,但HttpClient有一大堆请求的异步方法。
上述就是C#学习教程:如何在不中断async / await的情况下创建HttpWebRequest?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/962395.html