c# - 将使用 WebClient 的同时下载转换为 HttpClient
问题描述
我有一个创建多个对象的 WinForms 应用程序,每个对象都有自己的 WebClient 并在其构造函数上调用 DownloadStringAsync。当回调 DownloadStringAsyncComplete 被调用时,显示被更新。我想在这里保留的主要方面是能够同时执行多个请求,因为每个请求都需要几秒钟。如何使用 HttpClient 完成此操作?我无法等待 GetAsync,但是,我怎么知道每个响应何时到达?如果我确实等待 GetAsync,那么它们将一个接一个地执行,整个过程将需要很长时间......
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Net;
namespace RequestTest
{
public partial class Form1 : Form
{
List<Requester> requesters;
public Form1()
{
InitializeComponent();
requesters = new List<Requester>();
}
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 20; i++)
{
requesters.Add(new Requester(this));
}
}
public void SomeoneCompletedDownload()
{
textBox1.AppendText("sample text");
}
}
public class Requester
{
Form1 caller;
public Requester(Form1 _caller)
{
caller = _caller;
var client = new WebClient();
client.DownloadStringCompleted += DownloadCompleted;
client.DownloadStringAsync(new Uri("some-url"));
}
private void DownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
caller.SomeoneCompletedDownload();
}
}
}
解决方案
好的,我找到了自己的答案。我只是将请求移至一个可等待的方法。
该方法本身等待响应并调用回调。
但是在调用该方法时,我不会等待它完成。
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Http;
namespace RequestTest
{
public partial class Form1 : Form
{
List<Requester> requesters;
DateTime start;
int counter;
public Form1()
{
InitializeComponent();
requesters = new List<Requester>();
}
private async void button1_Click(object sender, EventArgs e)
{
start = DateTime.Now;
for (int i = 0; i < 30; i++)
{
requesters.Add(new Requester(this, i + 1));
// only one of the following 3 lines should be uncommented
//requesters[i].RequestWeb(); // this uses the old WebClient (~ 12 sec)
//await requesters[i].RequestHttp(); // this takes forever since requests are executed one at a time (~ 86 sec)
_ = requesters[i].RequestHttp(); // <-- This is the way to go for my app. Dispatch the request and continue executing discarding the result. Callback is called in the same method. (~ 13 sec, consistent with option #1)
}
}
public void SomeoneCompletedDownload(string page)
{
var elapsed = DateTime.Now - start;
counter++;
textBox1.AppendText($"#{counter}: Page {page} finished after {elapsed.TotalSeconds.ToString("N2")} seconds.\r\n");
}
}
public class Requester
{
Form1 caller;
string page;
string url;
public Requester(Form1 _caller, int _page)
{
caller = _caller;
page = _page.ToString();
url = "https://www.youtube.com/";
}
public void RequestWeb()
{
var client = new WebClient();
client.DownloadStringCompleted += DownloadCompleted;
client.DownloadStringAsync(new Uri(url));
}
public async Task RequestHttp()
{
var client = new HttpClient();
var response = await client.GetAsync(url);
caller.SomeoneCompletedDownload(page);
}
private void DownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
caller.SomeoneCompletedDownload(page);
}
}
}
推荐阅读
- bash - 当我在 mac 机器 OS high sierra 的终端中发出任何命令时出现“没有这样的文件或目录”错误
- javascript - javascript按距离对位置的json进行排序
- json - 解码数组时无法将数组解组为 Go 结构
- woocommerce - 存档产品页面不起作用
- json - RestSharp 和多个请求参数类型
- android - 即使应用程序关闭,在后台定期从 web api 获取数据的正确方法是什么?
- javascript - TypeError:按钮为空,但在控制台中工作正常
- azure-active-directory - 使用先前生成的令牌访问 onedrive
- angular - 角度对象数组调用
- java - Spark中map函数的通用功能