Csharp/C#教程:如何在不中断async / await的情况下创建HttpWebRequest?分享


如何在不中断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.CreateHttpClient.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

(0)
上一篇 2021年11月27日
下一篇 2021年11月27日

精彩推荐