C# – How to add request headers when using HttpClient

There are two ways add request headers when using HttpClient:

  • Add headers for all requests using HttpClient.DefaultRequestHeaders.
  • Add headers per request using HttpRequestMessage.Headers.

In this article, I’ll show examples of both ways to add request headers.

Add an unchanging header for all requests

Let’s say you’re adding an API Key header. It needs to be included in all requests and the value won’t change.

To add this request header, you can use HttpClient.DefaultRequestHeaders when you’re initializing the HttpClient instance, like this:

public class RandomNumberService { private readonly HttpClient HttpClient; private const string key = "123"; public RandomNumberService() { HttpClient = new HttpClient(); HttpClient.DefaultRequestHeaders.Add("ApiKey", key); } public async Task<string> GetRandomNumber() { var response = await HttpClient.GetAsync(GetRandomNumberUrl); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); } }
Code language: C# (cs)

Here’s what the request looks like in Fiddler:

GET https://localhost:12345/RandomNumber HTTP/1.1 Host: localhost:12345 ApiKey: 123
Code language: plaintext (plaintext)

It includes the ApiKey header in all requests. This only had to be configured once.

Add a header per request

To add a header per request, use HttpRequestMessage.Headers + HttpClient.SendAsync(), like this:

public class RandomNumberService { private readonly HttpClient HttpClient; private const string randomNumberUrl = "https://localhost:12345/RandomNumber"; public RandomNumberService() { HttpClient = new HttpClient(); } public async Task<string> GetRandomNumber(string Token) { using (var request = new HttpRequestMessage(HttpMethod.Get, randomNumberUrl)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Token); var response = await HttpClient.SendAsync(request); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); } } }
Code language: C# (cs)

First, it’s best practice to use a single HttpClient instance for multiple requests. Since you’re using a single instance, don’t use HttpClient.DefaultRequestHeaders for headers that need to be applied per request. It’s not thread-safe. This is why you have to use HttpRequestMessage.Headers instead.

Second, you have to use HttpClient.SendAsync() to send the request because there are no overloads of GetAsync() / PostAsync() that take an HttpRequestMessage parameter.

Here’s an example of what multiple requests look like in Fiddler:

GET https://localhost:12345/RandomNumber HTTP/1.1 Host: localhost:12345 Authorization: Bearer 11 GET https://localhost:12345/RandomNumber HTTP/1.1 Host: localhost:12345 Authorization: Bearer 12
Code language: plaintext (plaintext)

Notice a unique authorization header was added to each request.

GetWithHeadersAsync() extension method for per request headers

HttpClient.GetAsync() / PostAsync() are convenience methods. It would be nice if there were overloads of these that accepted a list of per request headers, but there aren’t.

If you don’t want to have HttpRequestMessage + SendAsync() all over the place, you can abstract that logic away by using extension methods. Here’s an example:

public static class HttpClientExtensions { public static async Task<HttpResponseMessage> GetWithHeadersAsync(this HttpClient httpClient, string requestUri, Dictionary<string, string> headers) { using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri)) { foreach(var header in headers) { request.Headers.Add(header.Key, header.Value); } return await httpClient.SendAsync(request); } } }
Code language: C# (cs)

You can use the extension method in a similar way that you’re used to using GetAsync():

public async Task<string> GetRandomNumber(string Token) { var response = await HttpClient.GetWithHeadersAsync(randomNumberUrl, new Dictionary<string, string>() { ["Authorization"] = $"Bearer {Token}" }); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); }
Code language: C# (cs)

This is just one extension method. You can use this as starting point. I wouldn’t bother adding extension methods for all possible overloads of GetAsync() or PostAsync().

Use HttpRequestHeaders properties for adding common headers

You can add any header using .Add(key, value). For common headers, such as Authorization, you can also add the header through properties in HttpRequestHeaders. This can help you avoid mistakes and improves readability.

For example, you can add the Authorization header in these two functionally equivalent ways:

//Option 1 request.Headers.Add("Authorization", $"Bearer {Token}"); //Option 2 - Using the common header property request.Headers.Authorization = new AuthenticationHeaderValue(scheme: "Bearer", parameter: Token);
Code language: C# (cs)

Leave a Comment