以下日期:
How to download files using HttpClient with a ProgressBar?
该项目为WinForms .NET 6
如何解决错误:
严重性代码说明项目文件行禁止显示状态错误CS1503参数2:无法从“系统.线程.任务.并行循环状态”转换为“系统.线程.取消令牌”WinFormsApp1 D:\Csharp\WinFormsApp1\ResourceDownloader.cs 63活动
在第63行
var dataBytes = await client.Value.GetByteArrayAsync(site, token);
全类代码:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace WinFormsApp1
{
public class ResourceDownloader
{
private static Lazy<HttpClient> client = new(() => {
HttpClientHandler handler = CreateHandler(autoRedirect: true);
var client = new HttpClient(handler, true) { Timeout = TimeSpan.FromSeconds(60) };
client.DefaultRequestHeaders.Add("User-Agent", @"Mozilla/5.0 (Windows NT 10; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0");
client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate");
client.DefaultRequestHeaders.ConnectionClose = true;
return client;
}, true);
private static HttpClientHandler CreateHandler(bool autoRedirect)
{
return new HttpClientHandler()
{
AllowAutoRedirect = autoRedirect,
CookieContainer = new CookieContainer(),
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
}
public record Website(string Url, byte[]? Data, bool Completed = true, Exception? Ex = null);
public record ProgressReport(Website Site, int PercentageComplete);
private static object syncObj = new object();
private static ConcurrentBag<Website> processed = default!;
private static int progressCount = 0;
private static int totalCount = 0;
public static bool IsBusy { get; internal set; } = false;
public static async Task<List<Website>> Download(IProgress<ProgressReport> progress, IList<string> sites, CancellationTokenSource cts)
{
IsBusy = true;
processed = new ConcurrentBag<Website>();
progressCount = 0;
totalCount = sites.Count;
try
{
ParallelOptions options = new()
{
MaxDegreeOfParallelism = 8,
CancellationToken = cts.Token
};
await Parallel.ForEach(sites, options, async (site, token) => {
try
{
var dataBytes = await client.Value.GetByteArrayAsync(site, token);
ReportProgress(progress, dataBytes, site, null);
}
catch (Exception ex)
{
ReportProgress(progress, null, site, ex);
}
});
}
// To Debug / Log
catch (TaskCanceledException) { Debug.Print("The operation was canceled"); }
finally { IsBusy = false; }
return processed.ToList();
}
private static void ReportProgress(IProgress<ProgressReport> progress, byte[]? data, string site, Exception? ex)
{
lock (syncObj)
{
progressCount += 1;
var percentage = progressCount * 100 / totalCount;
Website website = new(site, data, ex is null, ex);
processed.Add(website);
progress.Report(new ProgressReport(website, percentage));
}
}
}
}
1条答案
按热度按时间mrphzbgm1#
Parallel.ForEach
无法识别Task
,无法处理异步工作负载(至少不能正确处理),并且使用2个参数重载接受处理程序(如ForEach<TSource>(IEnumerable<TSource>, Action<TSource,ParallelLoopState>)
),使用ParallelLoopState
作为处理程序的第二个参数。您需要使用
Parallel.ForEachAsync
(例如,此重载接受Func<TSource, CancellationToken, ValueTask>
)来正确处理异步工作负载。