Use a Custom Content Negotiatior to always return JSON in ASP.NET Web API

The ASP.NET Web API pipeline decides the media formatter to use depending on the request. This complex decision making process occurs during the content negotiation and is handled by the DefaultContentNegotiator. If we need to support only a single format, say JSON, we can replace the default negotiator with a custom one that always returns JsonMediaTypeFormatter.

Source: Supporting only JSON in ASP.NET Web API – the right way

In such situations it is often suggested to remove other media type formatters and only leave JsonMediaTypeFormatter.

public static void Register(HttpConfiguration config)
{
    // clear all and re-add JsonMediaTypeFormatter:
    config.Formatters.Clear();
    config.Formatters.Add(new JsonMediaTypeFormatter());
}

However, the caveat here is that even though we cleared all other formatters; the entire content negotiation process is still happening – which is a tiny overhead, you shouldn’t really have to pay for. Because we do know the outcome already, so why waste any cycles at all with conneg?

Here is a custom implementation of IContentNegotiator interface that always returns JsonMediaTypeFormatter.

namespace App.Web.Http.Helpers
{
    public class AlwaysJsonContent : IContentNegotiator
    {
        private readonly JsonMediaTypeFormatter _jsonFormatter;

        public AlwaysJsonContent(JsonMediaTypeFormatter formatter)
        {
            _jsonFormatter = formatter;
        }

        public ContentNegotiationResult Negotiate(
                       Type type,
                       HttpRequestMessage request,
                       IEnumerable<MediaTypeFormatter> formatters)
        {
            // no complex logic. always return the json formatter
            var result = new ContentNegotiationResult(_jsonFormatter,
                             new MediaTypeHeaderValue("application/json"));
            return result;
        }
    }
}

Replace the default content negotiator in the HttpConfiguration during startup.

using App.Web.Http.Helpers;

namespace App.Web  
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
           var jsonFormatter = new JsonMediaTypeFormatter();

            // replace the default negotiator with the custom class
           config.Services.Replace(
                        typeof(IContentNegotiator), 
                        new AlwaysJsonContent(jsonFormatter));
        }
    }
}

With the above code in place, the web API will always yield JSON regardless of how the request looks like.

[RoutePrefix("api")]
public class MainController : ApiController  
{
    [Route("cars")]
    public List<Car> GetCars()
    {
        var cars = new List<Car>();

        cars.Add(new Car { Make = "Chevy", Year = 2004});
        cars.Add(new Car { Make = "Ford", Year = 2005});

        return cars;
    }
}

public class Car  
{
    public string Make { get; set; }

    public int Year { get; set; }
}

Related: