75

Is it possible to create a HTTP HEAD request with the new HttpClient in .NET 4.5? The only methods I can find are GetAsync, DeleteAsync, PutAsync and PostAsync. I know that the HttpWebRequest-class is able to do that, but I want to use the modern HttpClient.

2

4 Answers 4

136

Use the SendAsync method with an instance of HttpRequestMessage that was constructed using HttpMethod.Head .

GetAsync, PostAsync, etc are convenient wrappers around SendAsync; the less common HTTP methods such as HEAD, OPTIONS, etc, don't get a wrapper.

In short:

client.SendAsync(new HttpRequestMessage(HttpMethod.Head, url))

0
19

You may also do as follows to fetch just the headers:

this.GetAsync($"http://url.com", HttpCompletionOption.ResponseHeadersRead).Result;
5
  • 7
    The beauty of this approach is that it works even if the target server explicitly disallows HEAD requests (e.g. Amazon AWS).
    – Ian Kemp
    Apr 18, 2019 at 13:12
  • 10
    From a code standpoint, I like this option and Ian's remark is also an advantage. But I implemented this one and Smigs' answer and Smigs' answer performed considerably faster...granted, my Urls point to 30-100MB files which may have something to do with that. But this answer makes a GET request rather than a HEAD so keep that in mind.
    – jasonxz
    May 27, 2020 at 1:03
  • I'm getting a "method not allowed"
    – Enrico
    Jun 18, 2020 at 9:21
  • If there is connection change/ redirection, this solution actually follows the connection. Just retrieving the header of the original url will get you a 200 response even when doing a full get may actually fail. Mar 3, 2023 at 4:37
  • 1
    As @jasonxz observed, this does make a full GET request. It allows you to access the headers as soon as they're available, but still does pull the rest of the data down. So if you're trying to conserve bandwidth when you just want the headers but to not download a possibly large body, this isn't the solution.
    – wojtow
    Apr 23, 2023 at 1:28
6

I needed to do this, to get TotalCount of ATMs that I was returning from my Web API's GET Method.

When I tried @Smig's answer I got the following Response from my Web API.

MethodNotAllowed : Pragma: no-cache X-SourceFiles: =?UTF-8?B?dfdsf Cache-Control: no-cache Date: Wed, 22 Mar 2017 20:42:57 GMT Server: Microsoft-IIS/10.0 X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET

Had to built upon @Smig's answer to get this working successfully. I found out that the Web API methods needs to explicitly allow the Http HEAD verb by specifying it in the Action method as an Attribute.

Here's the complete code with inline explanation by way of code comments. I've removed the sensitive code.

In my Web Client:

        HttpClient client = new HttpClient();

        // set the base host address for the Api (comes from Web.Config)
        client.BaseAddress = new Uri(ConfigurationManager.AppSettings.Get("ApiBase"));
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add( 
          new MediaTypeWithQualityHeaderValue("application/json"));

        // Construct the HEAD only needed request. Note that I am requesting
        //  only the 1st page and 1st record from my API's endpoint.
        HttpRequestMessage request = new HttpRequestMessage(
          HttpMethod.Head, 
          "api/atms?page=1&pagesize=1");

        HttpResponseMessage response = await client.SendAsync(request);

        // FindAndParsePagingInfo is a simple helper I wrote that parses the 
        // json in the Header and populates a PagingInfo poco that contains 
        // paging info like CurrentPage, TotalPages, and TotalCount, which 
        // is the total number of records in the ATMs table.
        // The source code is pasted separately in this answer.
        var pagingInfoForAtms = HeaderParser.FindAndParsePagingInfo(response.Headers);

        if (response.IsSuccessStatusCode)
            // This for testing only. pagingInfoForAtms.TotalCount correctly
            //  contained the record count
            return Content($"# of ATMs {pagingInfoForAtms.TotalCount}");

            // if request failed, execution will come through to this line 
            // and display the response status code and message. This is how
            //  I found out that I had to specify the HttpHead attribute.
            return Content($"{response.StatusCode} : {response.Headers.ToString()}");
        }

In the Web API.

    // Specify the HttpHead attribute to avoid getting the MethodNotAllowed error.
    [HttpGet, HttpHead]
    [Route("Atms", Name = "AtmsList")]
    public IHttpActionResult Get(string sort="id", int page = 1, int pageSize = 5)
    {
        try
        {
            // get data from repository
            var atms =  _atmRepository.GetAll().AsQueryable().ApplySort(sort);
            // ... do some code to construct pagingInfo etc.
            // .......
            // set paging info in header.
            HttpContext.Current.Response.Headers.Add(
              "X-Pagination", JsonConvert.SerializeObject(paginationHeader));
            // ...
            return Ok(pagedAtms));
        }
        catch (Exception exception)
        {
            //... log and return 500 error
        }
    }

FindAndParsePagingInfo Helper method for parsing the paging header data.

public static class HeaderParser
{
public static PagingInfo FindAndParsePagingInfo(HttpResponseHeaders responseHeaders)
{
    // find the "X-Pagination" info in header
    if (responseHeaders.Contains("X-Pagination"))
    {
        var xPag = responseHeaders.First(ph => ph.Key == "X-Pagination").Value;

        // parse the value - this is a JSON-string.
        return JsonConvert.DeserializeObject<PagingInfo>(xPag.First());
    }

    return null;
}

public static string GetSingleHeaderValue(HttpResponseHeaders responseHeaders, 
    string keyName)
{
    if (responseHeaders.Contains(keyName))
        return responseHeaders.First(ph => ph.Key == keyName).Value.First();

    return null;
}

}

2
  • 1
    @Kiquenet Hi, I updated the answer with the HeaderParser.FindAndParsePagingInfo source.
    – Shiva
    Feb 28, 2018 at 16:26
  • What is paginationHeader variable in method IHttpActionResult Get ?
    – Kiquenet
    Mar 1, 2018 at 8:20
3

Solved it by doing

 var result = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, url));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.