WebClient下载等待与取消的通用实现方案技术问询
Alright, let's break down a solid, reusable pattern that fits all your requirements perfectly. Here's how to implement a WebClient download that waits for completion, checks an unmodifiable cancellation flag periodically, and sticks to your async/await constraints:
WebClient Generic Wait & Cancellable Download Pattern
Core Implementation
First, let's assume this is the unmodifiable cancellation flag class you're working with (we can only read its boolean property):
// Unmodifiable flag class (as per your constraints) public sealed class CancellationFlag { public bool ShouldCancel { get; } // Read-only, no way to modify this class from our code }
Now here's the download manager that handles the waiting, flag checks, and cancellation logic:
using System; using System.Net; using System.Threading; using System.Threading.Tasks; public class DownloadManager { public void Download(string downloadUrl, string saveFilePath, CancellationFlag cancellationFlag) { // Wrap async logic in Task.Run (permitted by your constraints) var downloadTask = Task.Run(async () => { using var webClient = new WebClient(); using var cancellationSource = new CancellationTokenSource(); // Spin up a background task to periodically check the unmodifiable flag var flagCheckTask = Task.Run(async () => { while (!cancellationSource.Token.IsCancellationRequested) { await Task.Delay(150); // Adjust interval based on responsiveness needs (100-500ms works well) if (cancellationFlag.ShouldCancel) { cancellationSource.Cancel(); break; } } }); try { // Execute the download with cancellation support await webClient.DownloadFileTaskAsync(new Uri(downloadUrl), saveFilePath, cancellationSource.Token); Console.WriteLine("Download completed successfully!"); } catch (OperationCanceledException) { // Clean up partial downloads if cancellation triggers Console.WriteLine("Download cancelled by external flag"); if (System.IO.File.Exists(saveFilePath)) { System.IO.File.Delete(saveFilePath); } } catch (Exception ex) { // Handle other download errors (e.g., network issues) Console.WriteLine($"Download failed: {ex.Message}"); } finally { // Ensure the flag-checking task gets cleaned up cancellationSource.Cancel(); await flagCheckTask; } }); // Block the current thread until download completes (meets your "wait before other operations" requirement) downloadTask.Wait(); } }
Key Details Explained
- Async/Await Compliance: All asynchronous logic is wrapped in
Task.Run(async () => { ... }), withWait()used to block the main thread until completion—exactly what your constraints allow. - Periodic Flag Checks: A background task polls the unmodifiable
ShouldCancelproperty at configurable intervals. When the flag is triggered, it cancels the download via aCancellationTokenSource. - Clean Cancellation Handling: If the download is cancelled, we delete any partial files to avoid leaving invalid data behind.
- Blocking Wait: The outer
downloadTask.Wait()ensures your code won't proceed to other operations until the download (or cancellation) is fully finished.
Usage Example
// Get your unmodifiable cancellation flag instance (from your existing code) var cancellationFlag = new CancellationFlag(); // Simulate an external trigger for cancellation (e.g., user clicking a cancel button) Task.Run(() => { Thread.Sleep(6000); // Cancel after 6 seconds // Note: In your real code, the ShouldCancel property would be updated by the unmodifiable class's internal logic }); // Run the download var manager = new DownloadManager(); manager.Download("https://example.com/large-document.pdf", @"C:\Downloads\my-document.pdf", cancellationFlag); // This code only runs AFTER the download completes or is cancelled Console.WriteLine("Download flow finished—proceeding with next operations");
Quick Notes
- Adjust Polling Interval: Tweak the
Task.Delay(150)value to balance responsiveness and CPU usage. Shorter intervals react faster but use more resources. - WebClient Alternative: If you can use
HttpClientinstead, the logic is nearly identical—just replaceDownloadFileTaskAsyncwith streaming the response to a file. - Error Handling: Expand the exception block to fit your needs (e.g., retry logic, logging to a file).
内容的提问来源于stack exchange,提问作者Metro Smurf
相关产品推荐
相关产品推荐

