When implemented using HttpClient shows the progress of the download file in .net

In the .net framework in order to achieve download the file and displays the progress of the case, the simplest approach is to use the WebClient class. Subscribe DownloadProgressChanged event on the line.

But unfortunately, WebClient which is not included in .net standard. In .net standard, the network should be http request, we have to use more of HttpClient . Also note that, UWP also has a HttpClient , although usage is almost, but the namespace is not the same, but the UWP is support for downloading progress, there will not elaborate.

If you want to download the file, we will use the HttpClient the GetByteArrayAsync this method. To achieve the download progress, it is up to how to do it? As the saying goes, no one on the package. Here we write an extension method, defined as follows:

public static class HttpClientExtensions
{
    public static Task<byte[]> GetByteArrayAsync(this HttpClient client, Uri requestUri, IProgress<HttpDownloadProgress> progress, CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }
}

Which is HttpDownloadProgress structure (reason not to use the class below me say) my own definition, as follows:

public struct HttpDownloadProgress
{
    public ulong BytesReceived { get; set; }

    public ulong? TotalBytesToReceive { get; set; }
}

BytesReceived representative of the number of bytes have been downloaded, TotalBytesToReceive represents the number of bytes to be downloaded, because the http response header will not necessarily return the length (content-length), it is set here to be empty.

Because we need to get from http response header to the content-length, and HttpClient own GetByteArrayAsync and no way to achieve, we need to shift to GetAsync this method. GetAsync This method has an overloaded https://docs.microsoft.com/zh-cn/dotnet/api/system.net.http.httpclient.getasync#System_Net_Http_HttpClient_GetAsync_System_Uri_System_Net_Http_HttpCompletionOption_System_Threading_CancellationToken_ its second argument is an enumeration, on behalf of what is when can I get response. According to demand, we should use here HttpCompletionOption.ResponseHeadersRead this.

In addition HttpClient source code can be obtained at Github point of view. https://github.com/dotnet/corefx/blob/d69d441dfb0710c2a34155c7c4745db357b14c96/src/System.Net.Http/src/System/Net/Http/HttpClient.cs we can refer to the realization GetByteArrayAsync.

On reflection, we can write the following code:

public static class HttpClientExtensions
{
    private const int BufferSize = 8192;

    public static async Task<byte[]> GetByteArrayAsync(this HttpClient client, Uri requestUri, IProgress<HttpDownloadProgress> progress, CancellationToken cancellationToken)
    {
        if (client == null)
        {
            throw new ArgumentNullException(nameof(client));
        }

        using (var responseMessage = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false))
        {
            responseMessage.EnsureSuccessStatusCode();

            var content = responseMessage.Content;
            if (content == null)
            {
                return Array.Empty<byte>();
            }

            var headers = content.Headers;
            var contentLength = headers.ContentLength;
            using (var responseStream = await content.ReadAsStreamAsync().ConfigureAwait(false))
            {
                var buffer = new byte[BufferSize];
                int bytesRead;
                var bytes = new List<byte>();

                var downloadProgress = new HttpDownloadProgress();
                if (contentLength.HasValue)
                {
                    downloadProgress.TotalBytesToReceive = (ulong)contentLength.Value;
                }
                progress?.Report(downloadProgress);

                while ((bytesRead = await responseStream.ReadAsync(buffer, 0, BufferSize, cancellationToken).ConfigureAwait(false)) > 0)
                {
                    bytes.AddRange(buffer.Take(bytesRead));

                    downloadProgress.BytesReceived += (ulong)bytesRead;
                    progress?.Report(downloadProgress);
                }

                return bytes.ToArray();
            }
        }
    }
}

Here I will set the buffer to 8192 bytes (8 KB), equivalent to 8 KB per read report once the download progress, of course Tell me what you can put this small value adjustment, this would be better, but the relative performance Some backward. But also because there is a relatively high frequency Report, so HttpDownloadProgress not suitable for class (or GC will be under great pressure).

Now I own Demo renderings:

iiiw

Guess you like

Origin www.cnblogs.com/h82258652/p/10950580.html