How to cancel await async task ?

rhodanny 166 Reputation points
2023-12-28T22:30:46.53+00:00

This is the class for the downloading

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;

namespace Downloading_Test
{
    public class DownloadingCore
    {
        public class DownloadeCompletedEventArgs : EventArgs
        {
            public bool IsSuccess { get; set; }
            public string FilePath { get; set; } = string.Empty; // Initialize with an empty string
        }

        public class DownloadProgressEventArgs : EventArgs
        {
            public int Percentage { get; set; }
        }

        public class DownloadManager
        {
            public long ContentLength { get; private set; } // Expose ContentLength as a property

            public event EventHandler<DownloadeCompletedEventArgs>? DownloadCompleted;
            public event EventHandler<DownloadProgressEventArgs>? DownloadProgress;

            public async Task StartDownload(string url, string filePath)
            {
                try
                {
                    using (var client = new HttpClient())
                    {
                        var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
                        response.EnsureSuccessStatusCode();

                        ContentLength = response.Content.Headers.ContentLength.GetValueOrDefault(); // Set ContentLength

                        var totalBytesRead = 0L;

                        using (var contentStream = await response.Content.ReadAsStreamAsync())
                        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
                        {
                            var buffer = new byte[8192];
                            int bytesRead;
                            while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                            {
                                await fileStream.WriteAsync(buffer, 0, bytesRead);
                                totalBytesRead += bytesRead;

                                if (ContentLength > 0)
                                {
                                    var progressPercentage = (int)((float)totalBytesRead / ContentLength * 100);
                                    OnDownloadProgress(new DownloadProgressEventArgs { Percentage = progressPercentage });
                                }
                            }
                        }

                        OnDownloadCompleted(new DownloadeCompletedEventArgs { IsSuccess = true, FilePath = filePath });
                    }
                }
                catch (Exception ex)
                {
                    string exx = ex.ToString();
                    OnDownloadCompleted(new DownloadeCompletedEventArgs { IsSuccess = false, FilePath = filePath });
                }
            }

            protected virtual void OnDownloadCompleted(DownloadeCompletedEventArgs e)
            {
                DownloadCompleted?.Invoke(this, e);
            }

            protected virtual void OnDownloadProgress(DownloadProgressEventArgs e)
            {
                DownloadProgress?.Invoke(this, e);
            }
        }
    }
}

This is the form1 code. I added a variable s_cts and make instance for CancellationTokenSource.

In the button click event where the downloading start, I change the button text to "Stop"

and then I want that when the button text is Stop and then if clicking the button, it will stop everything in the middle and will reset everything and change the button text back to "Download"

using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using Downloading_Test;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace Downloading_Test
{
    public partial class Form1 : Form
    {
        private string _saveDir = @"D:\Downloads\";
        private DownloadingCore.DownloadManager _downloadManager = new DownloadingCore.DownloadManager();
        private string _fileUrl = "https://hil-speed.hetzner.com/100MB.bin";
        private Stopwatch _stopwatch = new Stopwatch();
        private DateTime _startTime;
        private TimeSpan _elapsedTime;
        private Logger logger = new Logger();
        private int downloadsCounter = 0;
        private CancellationTokenSource s_cts = new CancellationTokenSource();

        List<string> sites = new List<string>
            {
                "https://hil-speed.hetzner.com/100MB.bin",
                "https://hil-speed.hetzner.com/100MB.bin",
                "https://hil-speed.hetzner.com/100MB.bin"
                // Add more URLs as needed
            };

        public Form1()
        {
            InitializeComponent();

            InitializeDownloadManager();
        }

        private void InitializeDownloadManager()
        {
            _downloadManager.DownloadProgress += DownloadManager_DownloadProgress;
            _downloadManager.DownloadCompleted += DownloadManager_DownloadCompleted;
        }

        private void DownloadManager_DownloadCompleted(object? sender, DownloadingCore.DownloadeCompletedEventArgs e)
        {
            logger.LogDownloadCompleted(e.IsSuccess, _elapsedTime);

            progressBar1.Value = 0;
            _stopwatch.Stop();

            if (e.IsSuccess && downloadsCounter > 0)
            {
                downloadsCounter--;
            }

            if (downloadsCounter == 0)
            {
                logger.LogDownloadCompleted();
                Download.Enabled = true;
            }

            logger.GetLog(richTextBoxLogger);
        }

        private void DownloadManager_DownloadProgress(object? sender, DownloadingCore.DownloadProgressEventArgs e)
        {
            progressBar1.Value = e.Percentage;

            if (_stopwatch.IsRunning)
            {
                // Calculate elapsed time since the download started
                _elapsedTime = DateTime.Now - _startTime;

                if (_elapsedTime.TotalSeconds > 0)
                {
                    // Calculate the actual number of bytes downloaded
                    long totalBytes = e.Percentage * _downloadManager.ContentLength / 100;

                    // Calculate download speed
                    double speed = totalBytes / _elapsedTime.TotalSeconds;

                    // Calculate time left to download
                    double remainingBytes = _downloadManager.ContentLength - totalBytes;
                    double remainingTime = (speed > 0) ? remainingBytes / speed : 0;

                    // Update labels
                    labelDownloadSpeed.Text = "Speed: " + FormatBytes(speed) + "/s";
                    labelProgress.Text = $"Downloaded: {FormatBytes(totalBytes)} / {FormatBytes(_downloadManager.ContentLength)}";
                    labelTimeLeft.Text = "Time Left: " + FormatTimeSpan(TimeSpan.FromSeconds(remainingTime));
                    labelTimeElapsed.Text = "Time Elapsed: " + FormatTimeSpan(_elapsedTime);
                }
            }
        }


        public static string FormatBytes(double bytes)
        {
            const int scale = 1024;
            string[] units = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };

            if (bytes <= 0)
            {
                return "0 B";
            }

            int magnitude = (int)Math.Floor(Math.Log(bytes, scale));
            int index = Math.Min(magnitude, units.Length - 1);

            double adjustedSize = bytes / Math.Pow(scale, index);
            string format = (index >= 0 && index < 3) ? "F2" : "F0";

            return $"{adjustedSize.ToString(format)} {units[index]}";
        }

        private async void Download_Click(object sender, EventArgs e)
        {
            Download.Text = "Stop";

            downloadsCounter = sites.Count;

            foreach (string site in sites)
            {
                var fileName = Path.GetFileName(site);
                var fileSavePath = Path.Combine(_saveDir, fileName);

                try
                {
                    logger.LogStartDownload(fileName, site);
                    logger.GetLog(richTextBoxLogger);

                    _stopwatch.Reset();
                    _stopwatch.Start();
                    _startTime = DateTime.Now;

                    if (File.Exists(fileSavePath))
                    {
                        File.Delete(fileSavePath);
                    }
                    await _downloadManager.StartDownload(site, fileSavePath);
                }
                catch (Exception ex)
                {
                    logger.LogDownloadCompleted(false, _elapsedTime);
                }
            }
        }

        private string FormatTimeSpan(TimeSpan timeSpan)
        {
            return $"{timeSpan.Hours:D2}:{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}";
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {

        }
    }
}
Developer technologies Windows Forms
Developer technologies C#
0 comments No comments
{count} votes

Accepted answer
  1. gekka 12,206 Reputation points MVP Volunteer Moderator
    2023-12-29T03:46:19.81+00:00
    public async Task StartDownload(string url, string filePath, CancellationToken token) /* add token */
    {
        try
        {
            using (var client = new HttpClient())
            {
                var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token); /* add token */
                response.EnsureSuccessStatusCode();
    
                ContentLength = response.Content.Headers.ContentLength.GetValueOrDefault();
    
                var totalBytesRead = 0L;
    
                using (var contentStream = await response.Content.ReadAsStreamAsync())
                using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
                {
                    var buffer = new byte[8192];
                    int bytesRead;
                    while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) /* add token */
                    {
                        await fileStream.WriteAsync(buffer, 0, bytesRead , token); /* add token */
                        totalBytesRead += bytesRead;
    
    private async void Download_Click(object sender, EventArgs e)
    {
        if (Download.Text == "Stop")
        {
            s_cts?.Cancel();
            return;
        }
    
        Download.Text = "Stop";
    
        downloadsCounter = sites.Count;
    
        using (s_cts = new CancellationTokenSource())
        {
            foreach (string site in sites)
            {
                if (s_cts.IsCancellationRequested)
                {
                    break;
                }
    
                var fileName = Path.GetFileName(site);
                var fileSavePath = Path.Combine(_saveDir, fileName);
                try
                {
                            logger.LogStartDownload(fileName, site);
                            logger.GetLog(richTextBoxLogger);
    
                            _stopwatch.Reset();
                    _stopwatch.Start();
                    _startTime = DateTime.Now;
    
                    if (File.Exists(fileSavePath))
                    {
                        File.Delete(fileSavePath);
                    }
    
    
                    await _downloadManager.StartDownload(site, fileSavePath, s_cts.Token); /* add token */
                }
                catch (Exception ex)
                {
                    logger.LogDownloadCompleted(false, _elapsedTime);
                }
            }
        }
        s_cts = null;
        Download.Text = "Download";
    }
    
    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.