Search code examples
c#progress-barhttpclient

HttpClient with output of information about the download process


I've been stuck for three weeks with solving a problem in C#. Namely, not so long ago I noticed on the language documentation site that the WebClient class is not recommended to use, it is better to use HttpClient instead. enter image description here This is a good suggestion, but when I started using it, I noticed that it was impossible to get progress on the execution of the process, that is, if I download a file, I will not know how much was downloaded/there was also other technical information that was easily available in WebClient. So here's the question. There is such a piece of code and I can't understand why progressMessageHandler does not output information about the download process and if this is not the best way to get information about the download, what can you advise WITHOUT WebClient?..

string textDownloadProgress;
    private async void DownloadFileAsync()
    {
            string filename = "file.zip";
            var handler = new HttpClientHandler() { AllowAutoRedirect = true };
            var ph = new ProgressMessageHandler(handler);
            var hm = new HttpRequestMessage() { RequestUri = new Uri("URL") };
            var client = new HttpClient(ph) { Timeout = Timeout.InfiniteTimeSpan };

            var progressMessageHandler = new ProgressMessageHandler(new HttpClientHandler());
            progressMessageHandler.HttpReceiveProgress += (_, e) =>
            {
                textDownloadProgress += e.ProgressPercentage;
            };

            using (var filestream = new FileStream(filename, FileMode.Create))
            {
                var netstream = await client.GetStreamAsync(hm.RequestUri);
                await netstream.CopyToAsync(filestream);
            }
     }

I will be very grateful for your help, I have spent a lot of time and effort, but I have not found a decent solution…


Solution

  • Your prolem is that you are creating a new ProgressMessageHandler to assign the event handler, and doing nothing with that object.

    Instead assign the event handler to ph, which is the handler you are actually using.

    Note that you should ideally put HttpClient in a static field to prevent socket exhaustion (but if not then at least dispose it with using).

    Also hm and netstream need disposing. And you shouldn't use async void normally.

    private async Task DownloadFileAsync()
    {
        string filename = "file.zip";
        using var ph = new ProgressMessageHandler(new HttpClientHandler() { AllowAutoRedirect = true });
        using var client = new HttpClient(ph) { Timeout = Timeout.InfiniteTimeSpan };
    
        ph.HttpReceiveProgress += (_, e) =>
        {
            textDownloadProgress += e.ProgressPercentage;
        };
    
        using var hm = new HttpRequestMessage(HttpMethod.Get, new Uri("URL"));
        using var filestream = new FileStream(filename, FileMode.Create);
        using var netstream = await client.GetStreamAsync(hm.RequestUri);
        await netstream.CopyToAsync(filestream);
    }