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)