1

I am successfully downloading files with below code. Since I want them to be downloaded on Application Startup I do not want to block anything -> async.

However I am facing the problem that even when the URI path is complete nonsense it will generate me an empty file, instead of raising the error like stated in msdn

Can anyone help me?

private void DownloadDocuments()
    {
        using (WebClient myWebClient = new WebClient())
        {
            try
            {
                Log("load1");
                myWebClient.DownloadFileAsync(new Uri(documentsUri + documentActivation), documentspath + "\\" + documentActivation);

            }
            catch (WebException)
            {
                Log("Guide Activation Download failed.");
            }
            catch (InvalidOperationException)
            {
                Log("Guide Activation could not be saved.");
            }
        }
        using (WebClient myWebClient = new WebClient())
        { 
            try
            {
                Log("load2");
                myWebClient.DownloadFileAsync(new Uri(documentsUri + documentFloating), documentspath + "\\" + documentFloating);
            }
            catch (WebException)
            {
                Log("Guide Floating Download failed.");
            }
            catch (InvalidOperationException)
            {
                Log("Guide Floating could not be saved.");
            }
        }
        using (WebClient myWebClient = new WebClient())
        {
            try
            {
                Log("load3");
                myWebClient.DownloadFileAsync(new Uri(documentsUri + documentSeat), documentspath + "\\" + documentSeat);
            }
            catch (WebException)
            {
                Log("Guide Seat Download failed.");
            }
            catch (InvalidOperationException)
            {
                Log("Guide Seat could not be saved.");
            }
        }
    }
maccettura
  • 10,514
  • 3
  • 28
  • 35
  • 1
    As an aside, you should probably use `UriBuilder` instead of manually concatenating Uris... – maccettura Sep 12 '18 at 15:12
  • 3
    You should use await with Task to handle the exceptions https://stackoverflow.com/questions/30534704/how-to-deal-with-exceptions-when-using-webclient-downloadfileasync – Arun Kumar Sep 12 '18 at 15:13
  • If you `await` the three `DownloadFileAsync` calls, the files will be retrieved one after the other instead of being downloaded in parallel. – Bouke Sep 12 '18 at 15:22
  • Why not use `HttpClient`? You can reuse the same instance for those three requests. (You could probably reuse the same instance of your `WebClient` also.) – Kenneth K. Sep 12 '18 at 16:37
  • @Bouke DownloadFileAsync cannot be awaited since it is not returning anything – wulfithewulf Sep 13 '18 at 09:14
  • @Kenneth K. `WebClient` does not support parallel downloads, I will look through `HttpClient`, thank you. – wulfithewulf Sep 13 '18 at 09:16
  • @wulfithewulf Have you checked my answer? It does download files in parallel using *WebClient*. However, I also recommend *HttpClient* but my solution can be easily reworked to use that. – Adam Simon Sep 13 '18 at 11:34
  • yeah I tried and it worked, I did some adjustments to fit best, but now it works as I wnated it. What I referred to is, that you cannot have parallel downloading with the same resource (in the same `using` statement) – wulfithewulf Sep 13 '18 at 12:20
  • As you need to download only 3 files, creating a separate *WebClient* instance for each request doesn't matter much. If you downloaded, say, 100 files, then [a single, re-used *HttpClient*](https://stackoverflow.com/questions/11178220/is-httpclient-safe-to-use-concurrently) would be definitely advisable. – Adam Simon Sep 13 '18 at 13:00
  • yes you are definitely right but, for this special situation, for which I can foresee will not change, the WebClient seems less work – wulfithewulf Sep 14 '18 at 13:31

1 Answers1

4

WebClient.DownloadFileAsync doesn't throw exceptions on HTTP request failures. You need to subscribe to the DownloadFileCompleted event to get notified of errors.

However, I don't recommend messing with event handler callbacks once we have the task-based async/await feature in C#: WebClient.DownloadFileTaskAsync is much more convenient to use.

With your comment about parallel processing in mind, you can do something like this:

static async Task DownloadDocumentAsync(Uri uri, string fileName)
{
    using (var webClient = new WebClient())
    {
        try
        {
            await webClient.DownloadFileTaskAsync(uri, fileName);
        }
        catch (WebException ex)
        {
            Log($"Downloading {uri} failed. {ex.Message}");
            throw;
        }
        catch (InvalidOperationException)
        {
            Log($"Saving {uri} to {fileName} failed. File is in use.");
            throw;
        }
    }
}

Then your logic at application startup:

var baseUri = new Uri(documentsUri);
var downloadTasks = new[]
{
    DownloadDocumentAsync(new Uri(baseUri, documentActivation), Path.Combine(documentspath, documentActivation)),
    DownloadDocumentAsync(new Uri(baseUri, documentFloating), Path.Combine(documentspath, documentFloating)),
    DownloadDocumentAsync(new Uri(baseUri, documentSeat), Path.Combine(documentspath, documentSeat)),
};

try
{
    Task.WaitAll(downloadTasks);
}
catch (AggregateException)
{
    // handle the case when some of the download tasks failed
}

This way the download tasks executes parallel but Task.WaitAll blocks until all of the tasks are completed. If you want to stay async, you need await Task.WhenAll instead.

Adam Simon
  • 2,762
  • 16
  • 22
  • thank you it worked. I do not need to try catch the `Task.WhenAll` since I do not throw the error again, since the only handling I would do, would be to delete the File with which occured an errror. But yeah thank you :) – wulfithewulf Sep 13 '18 at 12:23