ASP.NET Core – How to get request headers

There are two ways to get request headers:

  • Use the Request.Headers dictionary.
  • Use [FromHeader].

When a request comes in, the framework loads request headers into the Request.Headers dictionary. You can use this just like any other dictionary. Here’s an example of using TryGetValue() to check if a request header exists and get its value:

[HttpGet] public IActionResult Get() { if (Request.Headers.TryGetValue("testId", out var testId)) { //use testId value } return Ok(); }
Code language: C# (cs)

Note: To just check if a header exists, use Request.Headers.ContainsKey(“testId”).

The other option is to use the [FromHeader] attribute, which I’ll show below.

Using [FromHeader]

You can use the [FromHeader] attribute to automatically map request headers to parameters (or model properties). It maps them by matching the request header key with the parameter name.

Here’s an example of how to use [FromHeader]:

[HttpGet] public IActionResult Get([FromHeader] int? testId) { //use testId Console.WriteLine($"Got testId={testId}"); return Ok(); }
Code language: C# (cs)

Now send a request with a header:

GET /movie/ TestId: 2022 ..other headers...
Code language: plaintext (plaintext)

It outputs the following, showing that it mapped the TestId header to the testId parameter:

Got testId=2022
Code language: plaintext (plaintext)

Two things to notice:

  • It does case-insensitive name matching (ex: TestId matches testId).
  • Header values are strings, but you can map them to parameters with different types (ex: int). It will try to convert the header value to that type for you.

This saves quite a bit of coding effort compared to using Request.Headers manually.

Validation

One benefit of using [FromHeader] is that the framework will do validation. If you use Request.Headers manually, you have to do the validation logic yourself.

For example, when you use [FromHeader] on a non-string parameter, it has to convert the header value to the type. If this fails, it’ll return a validation error (400 – Bad Request), like this:

{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "0HMHV7HKJOJBG:00000002", "errors": { "": [ "The value 'a' is not valid." ] } }
Code language: JSON / JSON with Comments (json)

Note: This error message is lacking contextual info (such as the parameter name), but it’s better than nothing.

You can add additional attributes to do more validation. For example, let’s say you want to require a request header. Besides checking if the nullable parameter is null, or checking Request.Headers, you can put the [Required] attribute on the parameter:

[HttpGet] public IActionResult Get([Required][FromHeader]int testId)
Code language: C# (cs)

When the required header isn’t sent in, you’ll get an error like this:

{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "0HMHV98CF5VDC:00000002", "errors": { "testId": [ "The testId field is required." ] } }
Code language: JSON / JSON with Comments (json)

Headers with multiple values

Headers can have multiple values. If you are expecting multiple values, use an array parameter so it’ll automatically map the values into the array.

For example, let’s say your request has a header with multiple values (TestName has two values):

GET /employee/ TestName: Bob TestName: Alice ..other headers...
Code language: plaintext (plaintext)

To automatically map these values, add an array parameter and use [FromHeader]:

[HttpGet] public IActionResult Get([FromHeader] string[] testName) { //use testNames Console.WriteLine($"Got test names: {String.Join(" ", testName)}"); return Ok(); }
Code language: C# (cs)

This outputs the following:

Got test names: Bob Alice
Code language: plaintext (plaintext)

Warning: If you’re using a string parameter (not an array), it’ll map the multiple values to the string as comma-separated values (i.e. “Bob,Alice”). This can be surprising.

Mapping a header to a parameter with a different name

By default, request headers are mapped to parameters with the same name. If you want to map a request header to a parameter with a different name, use the Name parameter with [FromHeader].

For example, let’s say you want to map a header named TestId to a parameter named id. Here’s how to do that:

[HttpGet] public IActionResult Get([FromHeader(Name = "TestId")] string id) { //use id Console.WriteLine($"Got id={id}"); return Ok(); }
Code language: C# (cs)

Now send a request with the header:

GET /test/ TestId: Test1234
Code language: plaintext (plaintext)

This outputs the following:

Got id=Test1234
Code language: plaintext (plaintext)

Mapping to model properties

You can automatically map request headers to model properties by using [FromHeader]. You have to add it to the model properties and model parameter.

Here’s an example. First, add [FromHeader] to the model properties:

using Microsoft.AspNetCore.Mvc; public class Person { [FromHeader] public string Name { get; set; } }
Code language: C# (cs)

Then add [FromHeader] to the model parameter:

[HttpPost] public IActionResult Post([FromHeader]Person person) { //do something with model Console.WriteLine($"Got name={person.Name}"); return Ok(); }
Code language: C# (cs)

Now send a request with headers:

POST /person/ Name: Bob
Code language: plaintext (plaintext)

This outputs the mapped header value:

Got name=Bob

Looping through the request headers

Here’s how to loop through all request headers:

[HttpGet] public IActionResult Get() { foreach(var header in Request.Headers) { Console.WriteLine($"{header.Key}={header.Value}"); } return Ok(); }
Code language: C# (cs)

This is mostly helpful for debugging or logging purposes.

Getting request headers in an action filter or middleware

In middleware and action filters, you can access request headers through HttpContext.Request.Headers. Here are some code examples:

Leave a Comment