Reputation: 9530
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?
Upvotes: 141
Views: 225156
Reputation: 3553
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();
}
);
Upvotes: 15
Reputation: 178
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);
Upvotes: 3
Reputation: 146188
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")
{
}
}
Upvotes: 25
Reputation: 4677
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();
}
}
Upvotes: 11
Reputation: 1053
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.
Upvotes: 55
Reputation: 139226
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);
}
}
Upvotes: 1
Reputation: 28320
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"]
Upvotes: 52
Reputation: 2926
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();
}
Upvotes: 172