Reputation: 4752
My goal is to add certain custom headers to every outgoing JSON response. To do this, created a class that extends from SetDefaultContentHeaders JsonMediaTypeFormatter, and overrode the SetDefaultContentHeaders method like so:
public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
{
base.SetDefaultContentHeaders(type, headers, mediaType);
headers.Add("X-Answer", "42");
headers.Add("X-Question", "Unknown");
}
I then prepended my derived media type formatter to the formatters list:
config.Formatters.Insert(0, new MyMediaTypeFormatter());
And this solution seems to work for some requests, but not others. After some investigation, I discovered that if I include an 'Accept' header in the request, the response does not contain my custom headers! This was a bit surprising, because the response type still comes back application/json, suggesting either my formatter or the default json formatter is handling the response. The only thing I can think is that the code that calls SetDefaultContentHeaders
is in the JsonMediaTypeFormatter
, and that SetDefaultContentHeaders
is not virtual.
So - what is going on here? And what is the best way(s) to correct this?
Upvotes: 0
Views: 1050
Reputation: 14880
In my opinion, media type formatters are concerned with encoding related headers only. If you want to add custom headers, you should use DelegatingHandler
or ActionFilter
. You can apply both globally (inserting them in the appropriate collection in the configuration class) and per-action for the later. An example, using DelegatingHandler
would look like:
public class JsonHeaderHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage message, CancellationToken token)
{
var response = await base.SendAsync(message, token);
IEnumerable<string> contentTypes;
if(response.Headers.TryGetValues("Content-Type", out contentTypes))
{
// Check if there is an application/json Content-Type header
// There should be 0 or 1, a call to FirstOrDefault() would be fine
if(contentTypes.Any(ct => ct.Contains("application/json")))
{
response.Headers.Add("X-Answer", "42");
response.Headers.Add("X-Question", "Unknown");
}
}
return response;
}
}
// And using HttpConfiguration configuration
configuration.MessageHandlers.Add(new JsonHeaderHandler());
Upvotes: 2