You might need to get a file's download size from a URL before downloading it. To do so, you have to send a request with a HEAD method.
What is a Head method?
The HTTP HEAD method requests the headers that would be returned if the HEAD request's URL was instead requested with the HTTP GET method. For example, if a URL might produce a large download, a HEAD request could read its Content-Length header to check the filesize without actually downloading the file.
Source: Mozilla (MDN)
The HEAD method is identical to GET except that the server only returns message-headers in the response, without a message-body.
Source: .NET docs
How to send a request with a HEAD method?
First, get a new instance of the HttpClient class.
// HttpClient lifecycle management best practices:
// https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use
var client = new HttpClient();
Create a new HttpRequestMessage which you can specify the HttpMethod to use.
// using System.Net.Http;
var request = new HttpRequestMessage(HttpMethod.Head, url);
Then, you need to send the request with the request message:
var response = await client.SendAsync(request);
After that, you need to read the ContentLength from the content headers.
if (response.IsSuccessStatusCode)
{
long? size = response.Content.Headers.ContentLength;
}
The ContentLength is in bytes, so if you want to display it to the user, you might want to use a NuGet package like ByteSize or similar to get a user friendly string.
Full Implementation
The following extension method returns the file size or null if it's not available.
public static class HttpExtensions
{
public static async Task<long?> GetFileSizeAsync(this HttpClient client, string url)
{
using (var request = new HttpRequestMessage(HttpMethod.Head, url))
using (var response = await client.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
return response.Content.Headers.ContentLength;
}
}
return null;
}
}
Alternative Implementation
If you prefer not using HttpRequestMessage, there is an alternative method:
public static async Task<long?> GetFileSizeAsync(this HttpClient client, string url)
{
using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
{
if (response.IsSuccessStatusCode)
{
return response.Content.Headers.ContentLength;
}
}
return null;
}
Usage
// HttpClient lifecycle management best practices:
// https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use
var client = new HttpClient();
var size = await client.GetFileSizeAsync("https://example.com/file.pdf");
Error Handling
The above implementation, checks if the server returns a success status code before reading the ContentLength from the response's content headers.
But it doesn't handles HttpRequestException which can still be thrown when the server is not available or when the internet connection is lost or etc. Make sure you handle this cases as well.
Summary
The both implementations are functionally the same, but I prefer using the HttpRequestMessage and explicitly specifying the Head method. The alternative approach sends a GET request but only reads the headers.
Top comments (0)