Add a custom response header in ApiController
Solution 1
I have entered comments, here is my complete answer.
You will need to create a custom filter and apply that to your controller .
public class CustomHeaderFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var count = actionExecutedContext.Request.Properties["Count"];
actionExecutedContext.Response.Content.Headers.Add("totalHeader", count);
}
}
In your Controller
public class AddressController : ApiController
{
public async Task<Address> Get()
{
Request.Properties["Count"] = "123";
}
}
Solution 2
You can explicitly add custom headers in a method like so:
[HttpGet]
[Route("home/students")]
public HttpResponseMessage GetStudents()
{
// Get students from Database
// Create the response
var response = Request.CreateResponse(HttpStatusCode.OK, students);
// Set headers for paging
response.Headers.Add("X-Students-Total-Count", students.Count());
return response;
}
For more information read this article: http://www.jerriepelser.com/blog/paging-in-aspnet-webapi-http-headers/
Solution 3
Simple solution is to write just this:
HttpContext.Current.Response.Headers.Add("MaxRecords", "1000");
Solution 4
What you need is:
public async Task<IHttpActionResult> Get()
{
var response = Request.CreateResponse();
response.Headers.Add("Lorem", "ipsum");
return base.ResponseMessage(response);
}
I hope this answers your question.
Solution 5
Alternatively, it’s better to leverage DelegatingHandler if it is something you need to perform on every response. Because it will work on the request/response pipeline and not on the controller/action level. In my case I must add some headers with every response, so I did what I described. See code snippet below
public class Interceptor : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Methods", "GET,POST,PATCH,DELETE,PUT,OPTIONS");
response.Headers.Add("Access-Control-Allow-Headers", "Origin, Content-Type, X-Auth-Token, content-type");
return response;
}
}
And you would be requiring to add this handler in WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new Interceptor());
}
}
Matias Cicero
Software Development Engineer @ Amazon Web Services
Updated on April 06, 2021Comments
-
Matias Cicero about 3 years
Until now, I had a
GET
method that looked like the following:protected override async Task<IHttpActionResult> GetAll(QueryData query) { // ... Some operations //LINQ Expression based on the query parameters Expression<Func<Entity, bool>> queryExpression = BuildQueryExpression(query); //Begin to count all the entities in the repository Task<int> countingEntities = repo.CountAsync(queryExpression); //Reads an entity that will be the page start Entity start = await repo.ReadAsync(query.Start); //Reads all the entities starting from the start entity IEnumerable<Entity> found = await repo.BrowseAllAsync(start, queryExpression); //Truncates to page size found = found.Take(query.Size); //Number of entities returned in response int count = found.Count(); //Number of total entities (without pagination) int total = await countingEntities; return Ok(new { Total = total, Count = count, Last = count > 0 ? GetEntityKey(found.Last()) : default(Key), Data = found.Select(e => IsResourceOwner(e) ? MapToOwnerDTO(e) : MapToDTO(e)).ToList() }); }
This worked like a charm and it was good. However, I was told recently to send the response metadata (that is,
Total
,Count
andLast
properties) as response custom headers instead of the response body.I cannot manage to access the
Response
from the ApiController. I thought of a filter or attribute, but how would I get the metadata values?I can keep all this information on the response and then have a filter that will deserialize the response before being sent to the client, and create a new one with the headers, but that seems troublesome and bad.
Is there a way to add custom headers directly from this method on an
ApiController
? -
Matias Cicero over 8 yearsBut how would I get the "values" of the headers?
-
Yousuf over 8 yearsInteresting Questions. It looks like you can set property Request.Properties["Count"] = "123" in controller and use it in the filter.
-
Yousuf over 8 yearsIn the filter, you can access it by actionContext.Request.Properties["Count"]
-
Matias Cicero over 8 yearsThis works perfectly but is it the correct way to do this? My metadata should be a property of the response, not the request. I mean, it works as a solution, but is it conceptually right?
-
weagle08 about 7 yearsI'm doing this, but the headers get stripped
-
Seagull about 7 years@weagle08 Does your request go through proxies? If so you can read this: stackoverflow.com/questions/20820572/…
-
nkalfov almost 7 yearsThis looks like double work to me. You may add a header directly
-
Admin over 6 yearsWorked for me but no proxy involved in our connection
-
Sten Petrov over 6 years@Nikola but then you lose the strongly typed response, which the OP didn't use but is still an option with this approach. I'm working on a web api project and not using strong types is causing issues - for one we can't easily generate correct swagger. Avoid returning untyped responses if you can
-
Deepak over 5 yearsThanks Darek, for code highlighting. I will make sure to do this from now onwards :)
-
Michael Erickson over 5 yearsIn my case I found this to be the best solution for returning response data in the headers, but you have to be careful where the action filter gets the data. I has to get the data for the request you are processing, I looked all over the place for data storage that is unique to the request and the only thing I could find is the "context.Request.Properties" table, which is most likely why @Yousuf used it. Keep in mine that the "context.Response" object does not exist while processing the action, so "context.Request" seems to be the only place you can store data like this.
-
Michael Erickson over 5 yearsRegarding strongly typed response, unfortunately that is the nature of the HTTP protocol, all data is text. You could consider some XML or JSON format that includes typing to verify the transfer of data.
-
ShellNinja about 5 yearsHttpContext would not be present in Controllers that derive ApiController.
-
Paul DeVito over 3 yearsThis is indeed to right answer if we're talking about a .net framework controller that derive from
system.web.http.apicontroller
. I'm personally just familiar with the core syntax, so this was great for this legacy project. cheers -
Andrew Gale about 3 yearsThis worked for me. My controller is inheriting from ApiController
-
Kit over 2 yearsAbsolute lifesaver in my legacy project.
-
Yossi Geretz over 2 yearsI used this in my class which derives from System.Web.Http.ApiController. (.NET Framework - 4.5.2.) Works perfectly.