How to add request headers when using HttpClient in C#

By FoxLearn Published on Mar 11, 2025   170
When using HttpClient to send requests in C#, there are two primary ways to add headers:
  1. Add headers globally for all requests using HttpClient.DefaultRequestHeaders.
  2. Add headers for individual requests using HttpRequestMessage.Headers.

Adding a Static Header for All Requests

If you need to include a fixed header, such as an API key that remains unchanged for every request, you can use HttpClient.DefaultRequestHeaders. This method ensures that the header is added to every request made by that instance of HttpClient.

For example, Adding a Static API Key Header

public class NumberService
{
    private readonly HttpClient HttpClient;
    private const string apiKey = "XYZ123";

    public NumberService()
    {
        HttpClient = new HttpClient();
        HttpClient.DefaultRequestHeaders.Add("ApiKey", apiKey);
    }

    public async Task<string> FetchRandomNumber()
    {
        var response = await HttpClient.GetAsync("https://localhost:12345/RandomNumber");
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();
    }
}

In this example, the ApiKey header is added once to HttpClient.DefaultRequestHeaders. This header will be included in every request without needing to add it manually each time.

Sample Request in Fiddler:

GET https://localhost:12345/RandomNumber HTTP/1.1
Host: localhost:12345
ApiKey: XYZ123

Adding a Header for Each Request

If the header value varies with each request (e.g., an Authorization token), you should add it to each individual request using HttpRequestMessage.Headers. This method ensures that headers are not shared across multiple requests.

For example, Adding a Token for Each Request

public class NumberService
{
    private readonly HttpClient HttpClient;
    private const string randomNumberUrl = "https://localhost:12345/RandomNumber";

    public NumberService()
    {
        HttpClient = new HttpClient();
    }

    public async Task<string> FetchRandomNumber(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();
        }
    }
}

Since we are dealing with a single HttpClient instance, it's crucial not to use DefaultRequestHeaders here, as it's not thread-safe. Instead, we add the header to the specific HttpRequestMessage.

Sample Requests in Fiddler:

GET https://localhost:12345/RandomNumber HTTP/1.1
Host: localhost:12345
Authorization: Bearer abc123

GET https://localhost:12345/RandomNumber HTTP/1.1
Host: localhost:12345
Authorization: Bearer def456

Each request includes a unique authorization token.

Using an Extension Method for Per-Request Headers

To simplify adding headers on a per-request basis, you can create an extension method. This will encapsulate the logic of creating a request and adding headers, so you don't have to repeat the code each time.

For example, Extension Method for HttpClient

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);
        }
    }
}

You can now call this method to make requests with headers:

public async Task<string> FetchRandomNumber(string token)
{
    var response = await HttpClient.GetWithHeadersAsync(randomNumberUrl, new Dictionary<string, string>
    {
        ["Authorization"] = $"Bearer {token}"
    });

    response.EnsureSuccessStatusCode();

    return await response.Content.ReadAsStringAsync();
}

This simplifies the process of sending requests with headers, without having to manually create an HttpRequestMessage and add headers each time.

Using HttpRequestHeaders Properties for Common Headers

For commonly used headers, such as Authorization, you can also use the properties provided in HttpRequestHeaders. This is not only more readable but can help avoid errors.

// Option 1: Using Add method
request.Headers.Add("Authorization", $"Bearer {token}");

// Option 2: Using the Authorization property
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);

Both approaches are functionally equivalent, but using the properties (like request.Headers.Authorization) makes the code cleaner and more maintainable.

By using the extension method, you can make your code cleaner and easier to maintain when you need per-request headers without constantly writing repetitive logic.