Ein eigener „Mini“-Downloadmanager

Hin und wieder kommt es vor, dass eine Anwendung Dateien aus dem Internet herunterladen muss. Oftmals soll hierfür auch eine Fortschrittsanzeige dargestellt werden, z.B. bei einer eigenen Update-Routine. Schön wäre es doch, wenn der Download gestartet wird, noch während man die Dateien für ein etwaiges Update zusammen sucht. Oder etwa nicht? Auch schön wäre es, wenn wir den Fortschritt des aktuellen Downloads erfahren könnten und wenn das Ganze anschließend auch noch sauber asynchron ausgeführt wird. Mithilfe der Klassen „WebClient“ und „Queue<T>“ können wir dies auch mit Leichtigkeit realisieren. Da ich den Quellcode bereits soweit vorbereitet habe, sehen wir uns das Ganze erst einmal an.

public class DownloadManager
{
    private readonly string _downloadDirectory;
    private bool _shouldAbort;

    private readonly Queue<string> _queue;
    private readonly WebClient _client;

    public double ProgressOfCurrentFile { get; private set; }

    public DownloadManager()
        : this(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads"))
    { }

    public DownloadManager(string downloadDirectory)
    {
        _downloadDirectory = downloadDirectory;

        _queue = new Queue<string>();
        _client = new WebClient();

        _client.DownloadProgressChanged += (sender, args) => ProgressOfCurrentFile = args.ProgressPercentage;
    }

    public void Enqueue(string file)
    {
        _queue.Enqueue(file);
    }

    public void Abort()
    {
        _shouldAbort = true;
        _queue.Clear();
    }

    public void DownloadFiles()
    {
        Task result = DownloadFilesAsync();
        result.Wait();
    }

    public async Task DownloadFilesAsync()
    {
        _shouldAbort = false;
        if (!Directory.Exists(_downloadDirectory))
            Directory.CreateDirectory(_downloadDirectory);

        while (_queue.Count > 0 && !_shouldAbort)
        {
            string path = _queue.Dequeue();
            string filename = path.Split(new[] {'/', '\\'}).Last();

            await Task.Run(() => _client.DownloadFile(new Uri(path), _downloadDirectory + "\\" + filename));
        }
    }
}

Was haben wir hier nun? Zwei Konstruktoren, der eine ohne Parameter nutzt als Ziel für die Downloads den Benutzer-Download-Ordner, während der andere einen frei angegebenen Pfad nutzt. Zusätzlich haben wir eine Methode um Dateien dem Download hinzuzufügen, sowie eine Methode um das Ganze abzubrechen (aktuell würde diese nur zwischen Downloads abbrechen aber keine aktiven Downloads!). Und zu guter Letzt natürlich noch unsere beiden eigentlichen Download-Methoden, die eine synchron, die andere ssynchron, wobei in diesem Fall die synchrone die asynchrone nutzt und einfach auf dessen ending wartet.