0
votes

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?

1

1 Answers

2
votes

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());