Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use HttpClient.DefaultRequestHeaders for stable headers sent by one client, HttpRequestMessage.Headers for a single request, and HttpContent.Headers for metadata about the request body. There is no standard “footer” collection on HttpClient. If by footer you mean an HTTP trailer, treat it as a separate protocol feature and verify support in your target .NET runtime, handler, HTTP version, and server before relying on it.

Choose the header collection that matches the job

Need Use Typical examples
Every request made by one client instance HttpClient.DefaultRequestHeaders Authorization, a stable User-Agent value, tenant or API-version metadata
One request only HttpRequestMessage.Headers Correlation ID, idempotency key, a one-off feature flag
Information describing the body HttpContent.Headers Content-Type, Content-Length, Content-Encoding
Reusable cross-cutting behavior A DelegatingHandler in the handler chain Adding a correlation ID, logging, or signing each outgoing request

These collections are not interchangeable. A request header describes the HTTP message or its context; a content header describes the bytes carried in the body.

Add a header to every request from one HttpClient

Set defaults during client configuration, before sending requests. Microsoft’s API documentation specifically warns: “DefaultRequestHeaders should not be modified while there are outstanding requests.” Treat the collection as configuration, not per-request mutable state.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", accessToken);
client.DefaultRequestHeaders.Add("X-Client-Version", "2026.09");

using var response = await client.GetAsync("https://api.example.com/items");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();

The token variable and endpoint above are illustrative. In an application, obtain credentials from a protected configuration system and avoid logging them. If a value changes for each operation, do not mutate the defaults while requests are running; put that value on the individual request instead.

Typed and factory-created clients

When using IHttpClientFactory, configure stable defaults in the client registration or typed-client constructor. This keeps lifetime management separate from request-specific data. A per-user access token is usually request data unless the client instance is deliberately isolated to one identity.

Add a header to one request

Create an HttpRequestMessage, add the header to its Headers collection, send it, and dispose it when finished.

using var request = new HttpRequestMessage(
    HttpMethod.Get,
    "https://api.example.com/items");
request.Headers.Add("X-Request-Id", requestId);
request.Headers.Add("X-Feature", "preview");

using var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();

This scope is ideal for correlation IDs, conditional behavior, one-time authorization, and values supplied by the current operation. A header added to the message does not silently become a default for later requests.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use typed properties when available

Many standard headers have strongly typed properties that validate formatting:

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", accessToken);
request.Headers.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

For a non-standard name, Add is appropriate. If a server requires an unusual value, confirm its grammar and whether the value belongs to request or content headers.

Put Content-Type and other body metadata on HttpContent

Content-Type describes the representation in the body, so set it through the content object’s headers. HttpContentHeaders exposes the content-header collection and its ContentType property.

using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

var json = "{"name":"Ada"}";
using var content = new StringContent(
    json,
    Encoding.UTF8,
    "application/json");

using var response = await client.PostAsync(
    "https://api.example.com/items",
    content);
response.EnsureSuccessStatusCode();

The StringContent constructor sets the media type and encoding for this example. You can also assign it explicitly:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
content.Headers.ContentType =
    new MediaTypeHeaderValue("application/json");

Do not force Content-Type into request.Headers. The content collection is where the runtime and handlers expect body metadata, and it avoids confusing validation errors.

Other content examples

  • ByteArrayContent is suitable for already-encoded bytes; set its media type on content.Headers.ContentType.
  • FormUrlEncodedContent and MultipartFormDataContent provide content semantics for their formats; inspect or adjust their content headers only when the receiving API requires it.
  • Per-part headers in multipart requests belong to each part’s content headers, not the outer request headers.

When a DelegatingHandler is a better fit

A handler centralizes behavior that must run for many requests while remaining reusable and testable. It can add a header immediately before forwarding a request.

using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

public sealed class CorrelationHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        if (!request.Headers.Contains("X-Correlation-Id"))
            request.Headers.Add("X-Correlation-Id", Guid.NewGuid().ToString("N"));

        return base.SendAsync(request, cancellationToken);
    }
}

var handler = new CorrelationHandler
{
    InnerHandler = new HttpClientHandler()
};
using var client = new HttpClient(handler);

Use a handler for cross-cutting policy such as tracing, signing, or diagnostics. Keep secrets and mutable identity state out of shared handler fields unless the design explicitly synchronizes them.

What “footer” can mean

There is no HttpClient footer API

The standard HTTP abstractions documented for HttpClient expose request headers, response headers, and content headers. They do not define a generic footer collection. Do not invent a client.Footer property or send a made-up header named “footer”; an HTTP server will interpret that as an ordinary, unrelated header at best.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If you mean HTTP trailers

HTTP trailers are fields sent after the message body, usually when the body uses a framing mode that permits trailing metadata. They are not equivalent to a visual document footer and are not interchangeable with request headers. Whether trailers can be declared, emitted, read, or preserved depends on the .NET runtime, HTTP version, selected handler, request/response direction, and server or proxy.

The reviewed Microsoft API material does not settle a universal trailer-support recipe. Before implementing one, verify the exact runtime and protocol documentation for your deployment, then test through every intermediary. If the receiver actually needs a value before processing the body, send a normal request header or include the value in the body instead.

Complete examples in common calling styles

cURL equivalent for comparison

curl -H "X-Request-Id: 12345" 
     -H "Content-Type: application/json" 
     -d '{"name":"Ada"}' 
     https://api.example.com/items

Posting JSON with HttpClient

using System.Net.Http.Json;

using var request = new HttpRequestMessage(
    HttpMethod.Post,
    "https://api.example.com/items")
{
    Content = JsonContent.Create(new { name = "Ada" })
};
request.Headers.Add("X-Request-Id", requestId);

using var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();

Troubleshooting header failures

“Misused header name” or validation exception

Cause: a content header was added to request headers, or a restricted standard header was formatted incorrectly.

Fix: move body metadata to request.Content.Headers, use a typed property such as Authorization, and verify the value’s syntax.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The header appears on some calls but not others

Cause: the value was added to one HttpRequestMessage rather than the client defaults, or a different client instance is being used.

Fix: choose the intended scope explicitly and inspect the outgoing message in a safe test environment.

Changing a default causes intermittent behavior

Cause: DefaultRequestHeaders was modified while requests were outstanding.

Fix: configure defaults once before sending, or create a request message and set the changing value there.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The server ignores the custom header

Cause: a proxy, gateway, CORS policy, authentication layer, or server framework may remove or decline to use it.

Fix: confirm the header on the wire, check intermediary configuration, and read the API’s accepted-header documentation. A successfully transmitted header is not proof that the application will act on it.

Content-Type is missing or wrong

Cause: content was created without a media type, or the type was assigned to the wrong collection.

Fix: construct StringContent with an explicit media type or assign content.Headers.ContentType before sending.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability, and security considerations

  • Reuse a properly managed HttpClient rather than constructing one for every operation; configure stable defaults once.
  • Use cancellation tokens and explicit timeouts for calls that can block on DNS, connection, or response data.
  • Do not put passwords, bearer tokens, or personal data in diagnostic logs or custom headers unless the logging policy protects them.
  • Generate request IDs at the operation boundary and preserve them through retries so one logical operation can be traced.
  • Only retry when the method and server operation are safe to repeat, or when the API supplies an idempotency mechanism.

Or skip the browser setup

If your C# code needs a clean screenshot of a URL rather than a hand-managed browser, ScreenshotNeo exposes a GET endpoint that works directly with HttpClient. Cookie and consent banners, newsletter popups, and chat widgets are removed before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. Its MCP server lets Claude, Cursor, and other MCP clients call screenshot tools.

See the parameter reference in the ScreenshotNeo documentation. This C# example sends the API key and target URL as query parameters and writes the returned image:

using var http = new HttpClient();
var url = "https://stripe.com";
var endpoint = "https://api.screenshotneo.com/v1/shot" +
               "?access_key=" + Uri.EscapeDataString("YOUR_API_KEY") +
               "&url=" + Uri.EscapeDataString(url);

using var response = await http.GetAsync(endpoint);
response.EnsureSuccessStatusCode();
await using var output = File.Create("shot.webp");
await response.Content.CopyToAsync(output);

ScreenshotNeo includes full-page and element captures, device and retina settings, PDF output, custom CSS and JavaScript, waits, request blocking, cookies and headers, signed links, asynchronous jobs, bulk capture, caching, and an OpenAPI specification. Every feature is on every plan: 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

Frequently Asked Questions

Can I add the same header to every request without editing each call?

Yes. Configure DefaultRequestHeaders once on the client before sending requests.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should Content-Type be added to HttpRequestMessage.Headers?

No. Set it on the associated HttpContent.Headers, for example through StringContent or its ContentType property.

Is an HTTP trailer the same as a footer?

No. A trailer is protocol metadata sent after the body, and support must be verified for the exact runtime, handler, protocol, and server.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.