144

I am porting my API from Web API 2 to ASP.NET Core Web API. I used to be able to add a custom header in the following manner:

  HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
  response.Headers.Add("X-Total-Count", count.ToString());
  return ResponseMessage(response);

How does one add a custom header in ASP.NET Core Web API?

0

8 Answers 8

175

You can just hi-jack the HttpContext from the incoming Http Request and add your own custom headers to the Response object before calling return.

If you want your custom header to persist and be added in all API requests across multiple controllers, you should then consider making a Middleware component that does this for you and then add it in the Http Request Pipeline in Startup.cs

public IActionResult SendResponse()
{
    Response.Headers.Add("X-Total-Count", "20");

    return Ok();
}    
Sign up to request clarification or add additional context in comments.

1 Comment

in order to get the added value in fetch api u need to write this after fetch(url).then((response) => { console.log(response.headers.get('X-Total-Count')); return response.text(); })
58

For anyone who want to add custom header to all requests, middleware is the best way. make some change in startup.cs like this:

app.Use(async (context, next) =>
{
   context.Response.Headers.Add("X-Developed-By", "Your Name");
   await next.Invoke();
});

Good luck.

5 Comments

Modifying response directly in middleware is discouraged see here. Instead you can use context.Response.OnStarting callback.
This did not work in my middleware which captures exceptions. The DeveloperExceptionPageMiddleware would remove my header. Solution below by @Mojtaba works.
@BoukeVersteegh This certainly did not work in the specific circumstances you tested. The problem is not the solution
@Mojtaba, there is nothing wrong and discouraged about modifying the response directly in the middleware. The documentation actually provides examples of doing so. But it should be done before calling next. The warning is only about that point: the response should not be modified after calling next.
@Frédéric You are right. I adjusted my answer below to reflect your note.
52

There is an example for simple GET action which returns top X records from some list as well as the count in the response header X-Total-Count:

using System;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.Mvc;

namespace WebApplication.Controllers
{
    [Route("api")]
    public class ValuesController : Controller
    {
        [HttpGet]
        [Route("values/{top}")]
        public IActionResult Get(int top)
        {
            // Generate dummy values
            var list = Enumerable.Range(0, DateTime.Now.Second)
                                 .Select(i => $"Value {i}")
                                 .ToList();
            list.Reverse();

            var result = new ObjectResult(list.Take(top))
            {
                StatusCode = (int)HttpStatusCode.OK
            };

            Response.Headers.Add("X-Total-Count", list.Count.ToString());

            return result;
        }
    }
}

URL looks like http://localhost:3377/api/values/5 and results (for 19 dummy records generated, so X-Total-Count value will be 19) are like:

["Value 18","Value 17","Value 16","Value 15","Value 14"]

2 Comments

It feels hacky because we are basically setting the result and then properties on it in 2 places. It could be encapsulated in a custom action result. As I am typing I am just about to create an ContentResultWithHeaders. But having said that, it feels like a lot of effort.
The base class Microsoft.AspNetCore.Mvc.Controller already includes the property Response. Therefore, instead of calling Request.HttpContext.Response.Headers it's possible to simply call Response.Headers.
25

A custom attribute can be a good way.

https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2

public class AddHeaderAttribute : ResultFilterAttribute
{
    private readonly string _name;
    private readonly string _value;

    public AddHeaderAttribute(string name, string value)
    {
        _name = name;
        _value = value;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        context.HttpContext.Response.Headers.Add(_name, new string[] { _value });
        base.OnResultExecuting(context);
    }
}

Then use it like this on your API method

[AddHeader("X-MyHeader", "123")]

If you have a common header you can just extend this class :

public class MySpecialHeaderAttribute : AddHeaderAttribute
{
    public MySpecialHeaderAttribute() : base("X-MyHeader", "true")
    {
    }
}

1 Comment

This is a brilliant approach! Thank you so much. The attribute can also be applied to a Controller class. In my case, I created a SafeControllerBase which inherits from ControllerBase and attached the attribute(s) as needed. Now I am inheriting all controllers from SafeControllerBase, so the desired response is included to all responses.
15

I agree with @Ho3Ein that

if you want to add a custom header to all requests, middleware is the best way

but modifying Resposne directly in middleware (after calling next.Invoke()) is discouraged. From Microsoft Doc.

Changes to HttpResponse after the response has started, throw an exception. For example, changes such as setting headers and a status code throw an exception.

app.Use(async (context, next) =>
        {
            // Do work that doesn't write to the Response.
            await next.Invoke();
            // Do logging or other work that doesn't write to the Response.
        });

So the better way to add a custom header in middleware is to use Response.OnStarting callback like below:

app.Use(async (context, next) =>
                      {

                          context.Response.OnStarting(() =>
                              {
                                  context.Response.Headers.Add("X-Developed-By", "Your Name");
                                  return Task.FromResult(0);
                              });

                          await next();
                      }
                      );

5 Comments

Looks nice, but how can I pass there the count of returned records from request?
This is a wrong interpretation of the Microsoft documentation. The documentation only warns against touching the response after having executed the continuation next. Changing it before is fine.
@Frédéric well, two things here. First, in the context of this question, i.e., adding a custom header, the documentation explicitly gives a warning. Second, for example, what change do you want to do before calling next.Invoke()?
The warning is only against changing the response after calling next. Do add your header before calling next. Like in this other Microsoft documentation.
@Frédéric You are right. I adjusted my answer.
11

Other middleware might clear out headers after you set them. To make sure your headers are added, add them just before the response is sent.

app.Use(async (context, next) => {
    context.Response.OnStarting(() => {
        context.Response.Headers.Add("X-Developed-By", "Your Name");
        return Task.FromResult(0);
    });

    await next();
});

Or in a real middleware

public class AddHeadersMiddleware : IMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        context.Response.OnStarting(() => {
            context.Response.Headers.Add("X-Developed-By", "Your Name");
            return Task.FromResult(0);
        });

        await next();
    }
}

Comments

3

The selected answer is OK but if you want to add AES-like encoded values on headers you will get an Error:

Invalid non-ASCII or control character in header

One way to pass is encoding the value one more time with URL encoding. To do it:

string urlEncodedValue = WebUtility.UrlEncode(value);

Vice versa to decode it:

string value = WebUtility.UrlDecode(urlEncodedValue);

Comments

1

FWIW, if you have an ApiController, instead of a Controller, here is how you can do it:

public class InfoController : ApiController
{
    // Without custom header
    public IHttpActionResult MyMethod(..)
    {
        var myObject= GetMyResult();
        return Ok(myObject);
    }

    // With custom header
    public IHttpActionResult MyMethod(..)
    {
        var myObject = GetMyResult();

        // inspired from https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/content-negotiation#how-content-negotiation-works
        var negotiator = Configuration.Services.GetContentNegotiator();
        var result = negotiator.Negotiate(typeof(TypeOfMyObject), Request, Configuration.Formatters);
        var msg = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new ObjectContent<TypeOfMyObject>(myObject, result.Formatter,result.MediaType.MediaType)
        };

        msg.Headers.Add("MyCustomHeader", "MyCustomHeaderValue");
        return ResponseMessage(msg);
    }
}

1 Comment

ApiController is part of Microsoft.AspNetCore.Mvc.WebApiCompatShim.dll which is a temporary solution to ease migration from asp.net 4.x to asp.net core. for new code i would not use ApiController.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.