DEV Community

Peyman
Peyman

Posted on • Edited on

Get file size from a URL using HttpClient in .NET

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();
Enter fullscreen mode Exit fullscreen mode

Create a new HttpRequestMessage which you can specify the HttpMethod to use.

// using System.Net.Http;
var request = new HttpRequestMessage(HttpMethod.Head, url);
Enter fullscreen mode Exit fullscreen mode

Then, you need to send the request with the request message:

var response = await client.SendAsync(request);
Enter fullscreen mode Exit fullscreen mode

After that, you need to read the ContentLength from the content headers.

if (response.IsSuccessStatusCode)
{
    long? size = response.Content.Headers.ContentLength;
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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");
Enter fullscreen mode Exit fullscreen mode

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.

See also

Top comments (0)